C'è un motivo specifico per la scarsa leggibilità del design della sintassi delle espressioni regolari?


160

Tutti i programmatori sembrano concordare sul fatto che la leggibilità del codice è molto più importante delle linee di linea a sintassi breve che funzionano, ma richiedono uno sviluppatore senior per interpretare con qualsiasi grado di precisione - ma questo sembra essere esattamente il modo in cui sono state progettate le espressioni regolari. C'è stato un motivo per questo?

Siamo tutti d'accordo sul fatto che selfDocumentingMethodName()è molto meglio di e(). Perché ciò non dovrebbe valere anche per le espressioni regolari?

Mi sembra che invece di progettare una sintassi della logica a una riga senza organizzazione strutturale:

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})(0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

E questo non è nemmeno un rigoroso analisi di un URL!

Invece, potremmo rendere una struttura della pipeline organizzata e leggibile, per un esempio di base:

string.regex
   .isRange('A-Z' || 'a-z')
   .followedBy('/r');

Quale vantaggio offre la sintassi estremamente concisa di un'espressione regolare oltre all'operazione più breve possibile e alla sintassi logica? In definitiva, c'è un motivo tecnico specifico per la scarsa leggibilità del design della sintassi delle espressioni regolari?


I commenti non sono per una discussione estesa; questa conversazione è stata spostata in chat .
maple_shaft

1
Ho provato ad affrontare esattamente questo problema di leggibilità con una libreria chiamata RegexToolbox. Finora è stato portato su C #, Java e JavaScript - vedi github.com/markwhitaker/RegexToolbox.CSharp .
Mark Whitaker,

sono stati fatti molti tentativi per risolvere questo problema, ma la cultura è difficile da cambiare. vedi la mia risposta sulle espressioni verbali qui . Le persone cercano lo strumento comune più basso disponibile.
Parivar Saraff,

Risposte:


178

C'è una grande ragione per cui le espressioni regolari sono state progettate in modo così conciso come sono: sono state progettate per essere usate come comandi per un editor di codice, non come linguaggio per codificare. Più precisamente, è edstato uno dei primi programmi a usare espressioni regolari , e da lì le espressioni regolari hanno iniziato la loro conquista per il dominio del mondo. Ad esempio, il edcomando ha g/<regular expression>/ppresto ispirato un programma separato chiamato grep, che è ancora in uso oggi. A causa del loro potere, sono stati successivamente standardizzati e utilizzati in una varietà di strumenti come sedevim

Ma abbastanza per la curiosità. Quindi perché questa origine favorirebbe una grammatica concisa? Perché non si digita un comando dell'editor per leggerlo ancora una volta. È sufficiente che tu ricordi come metterlo insieme e che puoi fare le cose che vuoi fare. Tuttavia, ogni personaggio che devi digitare rallenta i tuoi progressi nella modifica del file. La sintassi delle espressioni regolari è stata progettata per scrivere ricerche relativamente complesse in un modo da buttare via, ed è proprio questo che dà alle persone mal di testa che le usano come codice per analizzare alcuni input di un programma.


5
regex non ha lo scopo di analizzare. in caso contrario, stackoverflow.com/questions/1732348/… . e mal di testa.
njzk2,

19
@ njzk2 Quella risposta è in realtà sbagliata. Un documento HTML non è un linguaggio normale, ma in realtà è un tag HTML aperto , che è ciò di cui si pone la domanda.
Casuale 832

11
Questa è una buona risposta che spiega perché regex originale è tanto enigmatico quanto lo è, ma non spiega perché attualmente non esiste uno standard alternativo con maggiore leggibilità.
Doc Brown,

13
Quindi, per coloro che pensano che grepsia un "afferrare" pronunciato male, viene in effetti da g/ re(per l'espressione regolare) / p?
Hagen von Eitzen,

6
@DannyPflughoeft No, non è così. Un tag aperto è solo <aaa bbb="ccc" ddd='eee'>, non ci sono tag nidificati al suo interno. Non puoi nidificare tag, ciò che annidi sono elementi (tag aperto, contenuti inclusi elementi figlio, tag chiuso), che la domanda non stava ponendo sull'analisi. I tag HTML sono un linguaggio normale: il bilanciamento / annidamento avviene a un livello superiore ai tag.
Casuale 832

62

L'espressione regolare che citi è un disastro terribile e non credo che nessuno sia d'accordo sul fatto che sia leggibile. Allo stesso tempo, gran parte di quella bruttezza è inerente al problema da risolvere: ci sono diversi livelli di annidamento e la grammatica dell'URL è relativamente complicata (certamente troppo complicata per comunicare in modo succinto in qualsiasi lingua). Tuttavia, è certamente vero che ci sono modi migliori per descrivere ciò che questa regex sta descrivendo. Quindi perché non sono usati?

Una grande ragione è l'inerzia e l'ubiquità. Non spiega come siano diventati così popolari in primo luogo, ma ora che lo sono, chiunque conosca le espressioni regolari può usare queste abilità (con pochissime differenze tra i dialetti) in cento lingue diverse e un migliaio di strumenti software aggiuntivi ( ad es. editor di testo e strumenti da riga di comando). A proposito, quest'ultimo non vorrebbe e non potrebbe usare alcuna soluzione che equivale a scrivere programmi , perché sono pesantemente utilizzati da non programmatori.

Nonostante ciò, le espressioni regolari sono spesso abusate, cioè applicate anche quando un altro strumento sarebbe molto meglio. Non penso che la sintassi della regex sia terribile . Ma è chiaramente molto meglio con schemi brevi e semplici: l'esempio archetipico di identificatori in linguaggi simili a C, [a-zA-Z_][a-zA-Z0-9_]*può essere letto con un minimo assoluto di conoscenza regex e una volta raggiunta quella barra è sia ovvio che piacevolmente succinto. Richiedere meno personaggi non è intrinsecamente negativo, anzi il contrario. Essere concisi è una virtù purché tu sia comprensibile.

Esistono almeno due motivi per cui questa sintassi eccelle in schemi semplici come questi: non richiede la fuga per la maggior parte dei caratteri, quindi legge in modo relativamente naturale e utilizza tutta la punteggiatura disponibile per esprimere una varietà di semplici combinatori di analisi. Forse ancora più importante, non richiede nulla per il sequenziamento. Scrivi la prima cosa, poi la cosa che viene dopo. Contrasta questo con il tuo followedBy, specialmente quando il seguente schema non è un'espressione letterale ma più complicata.

Quindi perché non riescono in casi più complicati? Vedo tre problemi principali:

  1. Non ci sono capacità di astrazione. Le grammatiche formali, che provengono dallo stesso campo dell'informatica teorica delle regex, hanno una serie di produzioni, quindi possono dare nomi a parti intermedie del modello:

    # This is not equivalent to the regex in the question
    # It's just a mock-up of what a grammar could look like
    url      ::= protocol? '/'? '/'? '/'? (domain_part '.')+ tld
    protocol ::= letter+ ':'
    ...
    
  2. Come abbiamo visto sopra, gli spazi bianchi senza significato speciale sono utili per consentire una formattazione più semplice per gli occhi. Stessa cosa con i commenti. Le espressioni regolari non possono farlo perché uno spazio è proprio questo, letterale ' '. Nota però: alcune implementazioni consentono una modalità "dettagliata" in cui gli spazi bianchi vengono ignorati e sono possibili commenti.

  3. Non esiste un meta-linguaggio per descrivere schemi e combinatori comuni. Ad esempio, si può scrivere una digitregola una volta e continuare a usarla in una grammatica libera dal contesto, ma non si può definire una "funzione" per così dire a cui viene data una produzione pe creare una nuova produzione che fa qualcosa in più con essa, ad esempio creare una produzione per un elenco separato da virgole di occorrenze di p.

L'approccio che proponi risolve certamente questi problemi. Semplicemente non li risolve molto bene, perché scambia molta più concisione per esso di quanto sia necessario. I primi due problemi possono essere risolti rimanendo in un linguaggio specifico del dominio relativamente semplice e conciso. Il terzo, beh ... una soluzione programmatica richiede ovviamente un linguaggio di programmazione per scopi generali, ma nella mia esperienza il terzo è di gran lunga il minore di questi problemi. Pochi schemi hanno abbastanza occorrenze dello stesso compito complesso che il programmatore desidera ardentemente per la capacità di definire nuovi combinatori. E quando ciò è necessario, la lingua è spesso abbastanza complicata da non poter e non essere comunque analizzata con espressioni regolari.

Esistono soluzioni per questi casi. Esistono circa diecimila librerie di combinatori di parser che fanno all'incirca ciò che proponete, solo con un diverso insieme di operazioni, spesso sintassi diverse e quasi sempre con più potere di analisi rispetto alle espressioni regolari (cioè, si occupano di linguaggi senza contesto o di dimensioni considerevoli sottoinsieme di quelli). Quindi ci sono generatori di parser, che seguono l'approccio "usa un DSL migliore" descritto sopra. E c'è sempre la possibilità di scrivere a mano parte dell'analisi, nel giusto codice. Puoi anche mescolare e abbinare, usando espressioni regolari per semplici compiti secondari e facendo le cose complicate nel codice invocando le regex.

Non so abbastanza dei primi anni dell'informatica per spiegare come le espressioni regolari siano diventate così popolari. Ma sono qui per restare. Devi solo usarli saggiamente e non usarli quando è più saggio.


9
I don't know enough about the early years of computing to explain how regular expressions came to be so popular.Tuttavia, possiamo ipotizzare che un motore di espressione regolare di base sia molto semplice da implementare, molto più semplice di un parser efficiente e privo di contesto.
biziclop,

15
@biziclop Non sopravvaluterei questa variabile. Yacc, che apparentemente aveva abbastanza predecessori per essere chiamato " ancora un altro compilatore di compilatore", è stato creato nei primi anni '70 ed è stato incluso in Unix una versione precedente grep(Versione 3 vs Versione 4). Sembra che il primo uso principale di regex sia stato nel 1968.

Posso solo andare su quello che ho trovato su Wikipedia (quindi non ci credo al 100%) ma secondo quello, è yaccstato creato nel 1975, l'intera idea dei parser LALR (che erano tra la prima classe di parser praticamente utilizzabili dei loro tipo) è nato nel 1973. Considerando che la prima implementazione del motore regexp che JIT ha compilato le espressioni (!) è stata pubblicata nel 1968. Ma hai ragione, è difficile dire cosa l'ha fatto oscillare, infatti è difficile dire quando i regex hanno iniziato a "prendere off". Ma sospetterei che una volta inseriti negli editor di testo utilizzati dagli sviluppatori, volessero usarli anche nel proprio software.
biziclop,

1
@ jpmc26 apre il suo libro, JavaScript The Good Parts to the Regex Chapter.
Viziionary,

2
with very few differences between dialectsNon direi che sono "pochissimi". Qualsiasi classe di caratteri predefinita ha diverse definizioni tra dialetti diversi. E ci sono anche stranezze di analisi specifiche per ogni dialetto.
nhahtdh,

39

Prospettiva storica

L'articolo di Wikipedia è abbastanza dettagliato sulle origini delle espressioni regolari (Kleene, 1956). La sintassi originale era relativamente semplice con solo *, +, ?, |e il raggruppamento (...). Era conciso ( e leggibile, i due non sono necessariamente opposti), perché i linguaggi formali tendono ad essere espressi con concise notazioni matematiche.

Più tardi, la sintassi e le capacità si sono evolute con gli editor e sono cresciute con Perl , che stava cercando di essere conciso dal design ( "le costruzioni comuni dovrebbero essere brevi" ). Ciò ha complicato molto la sintassi, ma nota che le persone sono ormai abituate alle espressioni regolari e sono brave a scriverle (se non a leggerle). Il fatto che a volte siano di sola scrittura suggeriscono che quando sono troppo lunghi, generalmente non sono lo strumento giusto. Le espressioni regolari tendono ad essere illeggibili quando vengono abusate.

Oltre le espressioni regolari basate su stringhe

Parlando di sintassi alternative, diamo un'occhiata a una già esistente ( cl-ppcre , in Common Lisp ). La tua espressione regolare lunga può essere analizzata ppcre:parse-stringcome segue:

(let ((*print-case* :downcase)
      (*print-right-margin* 50))
  (pprint
   (ppcre:parse-string "^(?:([A-Za-z]+):)?(\\/{0,3})(0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$")))

... e risulta nella seguente forma:

(:sequence :start-anchor
 (:greedy-repetition 0 1
  (:group
   (:sequence
    (:register
     (:greedy-repetition 1 nil
      (:char-class (:range #\A #\Z)
       (:range #\a #\z))))
    #\:)))
 (:register (:greedy-repetition 0 3 #\/))
 (:register
  (:sequence "0-9" :everything "-A-Za-z"
   (:greedy-repetition 1 nil #\])))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\:
    (:register
     (:greedy-repetition 1 nil :digit-class)))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\/
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\? #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\?
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\#
    (:register
     (:greedy-repetition 0 nil :everything)))))
 :end-anchor)

Questa sintassi è più dettagliata e, se si osservano i commenti di seguito, non necessariamente più leggibile. Quindi non dare per scontato che, poiché hai una sintassi meno compatta, le cose saranno automaticamente più chiare .

Tuttavia, se inizi a riscontrare problemi con le tue espressioni regolari, trasformarle in questo formato potrebbe aiutarti a decifrare ed eseguire il debug del codice. Questo è un vantaggio rispetto ai formati basati su stringhe, in cui un singolo carattere può essere difficile da individuare. Il vantaggio principale di questa sintassi è manipolare le espressioni regolari usando un formato strutturato anziché una codifica basata su stringhe. Ciò ti consente di comporre e costruire espressioni del genere come qualsiasi altra struttura di dati nel tuo programma. Quando uso la sintassi sopra, questo è generalmente perché voglio creare espressioni da parti più piccole (vedi anche la mia risposta CodeGolf ). Per il tuo esempio, possiamo scrivere 1 :

`(:sequence
   :start-anchor
   ,(protocol)
   ,(slashes)
   ,(domain)
   ,(top-level-domain) ... )

Le espressioni regolari basate su stringa possono anche essere composte, usando la concatenazione di stringhe o l'interpolazione racchiusa in funzioni di supporto. Tuttavia, ci sono limitazioni con le manipolazioni delle stringhe che tendono a ingombrare il codice (pensa ai problemi di annidamento, non diversamente dai backtick rispetto $(...)a bash; inoltre, i caratteri di escape possono farti venire il mal di testa).

Si noti inoltre che il modulo sopra consente i (:regex "string")moduli in modo da poter mescolare notazioni concise con alberi. Tutto ciò porta l'IMHO a una buona leggibilità e compostabilità; affronta i tre problemi espressi da delnan , indirettamente (cioè non nella lingua delle espressioni regolari stesse).

Concludere

  • Per molti scopi, la notazione concisa è in effetti leggibile. Ci sono difficoltà nel trattare le notazioni estese che implicano il backtracking, ecc., Ma il loro uso è raramente giustificato. L'uso ingiustificato di espressioni regolari può portare a espressioni illeggibili.

  • Le espressioni regolari non devono essere codificate come stringhe. Se hai una libreria o uno strumento che può aiutarti a costruire e comporre espressioni regolari, eviterai molti potenziali bug relativi alle manipolazioni delle stringhe.

  • In alternativa, le grammatiche formali sono più leggibili e sono migliori nella denominazione e nell'astrazione di sottoespressioni. I terminali sono generalmente espressi come semplici espressioni regolari.


1. Puoi preferire costruire le tue espressioni al momento della lettura, perché le espressioni regolari tendono ad essere costanti in un'applicazione. Vedi create-scannere load-time-value:

'(:sequence :start-anchor #.(protocol) #.(slashes) ... )

5
Forse sono solo abituato alla sintassi RegEx tradizionale, ma non sono così sicuro che 22 righe in qualche modo leggibili siano più facili da capire rispetto all'equivalente regex a una riga.

3
@ dan1111 "in qualche modo leggibile" ;-) D'accordo, ma se è necessario disporre di un tempo molto lungo regex, ha senso definire sottoinsiemi, come digits, idente li compongono. Il modo in cui lo vedo fatto è generalmente con manipolazioni di stringhe (concatenazione o interpolazione), che porta altri problemi come la corretta fuga. Cerca ad esempio le occorrenze dei \\\\`pacchetti in emacs. A proposito, questo è aggravata perché lo stesso carattere di escape viene utilizzato sia per i caratteri speciali come \ne \"e per la sintassi regex \(. Un esempio non lisp di buona sintassi è printf, dove %dnon è in conflitto \d.
coredump,

1
punto giusto sui sottoinsiemi definiti. Questo ha molto senso. Sono solo scettico sul fatto che la verbosità sia un miglioramento. Potrebbe essere più facile per i principianti (anche se concetti come greedy-repetitionnon sono intuitivi e devono ancora essere appresi). Tuttavia, sacrifica l'usabilità per gli esperti, poiché è molto più difficile vedere e comprendere l'intero modello.

@ dan1111 Sono d'accordo che la verbosità di per sé non è un miglioramento. Ciò che può essere un miglioramento è la manipolazione di regex utilizzando dati strutturati anziché stringhe.
coredump,

@ dan1111 Forse dovrei proporre una modifica usando Haskell? Parsec lo fa in sole nove righe; come una battuta: do {optional (many1 (letter) >> char ':'); choice (map string ["///","//","/",""]); many1 (oneOf "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."); optional (char ':' >> many1 digit); optional (char '/' >> many (noneOf "?#")); optional (char '?' >> many (noneOf "#")); optional (char '#' >> many (noneOf "\n")); eof}. Con poche righe come designare la stringa lunga come domainChars = ...e section start p = optional (char start >> many p)sembra piuttosto semplice.
CR Drost,

25

Il problema più grande con regex non è la sintassi eccessivamente concisa, è che proviamo ad esprimere una definizione complessa in una singola espressione, invece di comporla da blocchi più piccoli. Questo è simile alla programmazione in cui non si usano mai variabili e funzioni e invece si incorpora il codice in un'unica riga.

Confronta regex con BNF . La sua sintassi non è molto più pulita di regex, ma è usata in modo diverso. Si inizia definendo semplici simboli con nome e componendoli fino ad arrivare a un simbolo che descriva l'intero modello che si desidera abbinare.

Ad esempio, guarda la sintassi dell'URI in rfc3986 :

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
hier-part     = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty
...

È possibile scrivere quasi la stessa cosa usando una variante della sintassi regex che supporta l'incorporamento di sottoespressioni denominate.


Personalmente penso che una regex concisa come la sintassi vada bene per funzioni comunemente usate come classi di caratteri, concatenazione, scelta o ripetizione, ma per caratteristiche più complesse e più rare come i nomi prolissi del futuro sono preferibili. Abbastanza simile a come utilizziamo gli operatori come +o *nella normale programmazione e passiamo alle funzioni nominate per operazioni più rare.


12

selfDocumentingMethodName () è molto meglio di e ()

è? C'è un motivo per cui molte lingue hanno {e} come delimitatori di blocchi anziché BEGIN ed END.

Alle persone piace terseness e una volta che conosci la sintassi, la terminologia breve è migliore. Immagina il tuo esempio regex se d (per cifra) fosse "cifra", la regex sarebbe ancora più orribile da leggere. Se lo rendessi più facilmente analizzabile con i caratteri di controllo, sembrerebbe più XML. Né sono buoni una volta che conosci la sintassi.

Per rispondere correttamente alla tua domanda, però, devi capire che regex viene dai giorni in cui la terseness era obbligatoria. È facile pensare che un documento XML da 1 MB non sia un grosso problema oggi, ma stiamo parlando di giorni in cui 1 MB era praticamente l'intera capacità di archiviazione. Allora c'erano anche meno lingue usate, e regex non è a un milione di miglia da perl o C, quindi la sintassi sarebbe familiare ai programmatori del giorno che sarebbero felici di imparare la sintassi. Quindi non c'era motivo di renderlo più dettagliato.


1
selfDocumentingMethodNameè generalmente riconosciuto come migliore rispetto al efatto che l'intuizione del programmatore non si allinea alla realtà in termini di ciò che costituisce effettivamente leggibilità o codice di buona qualità . Le persone che concordano sono sbagliate, ma è così.
Leushenko,

1
@Leushenko: Stai dicendo che e()è meglio di selfDocumentingMethodName()?
Jacques B

3
@JacquesB forse non in tutti i contesti (come un nome globale). Ma per cose strettamente mirate? Quasi certamente. Sicuramente più spesso di quanto sagga la saggezza convenzionale.
Leushenko,

1
@Leushenko: faccio fatica a immaginare un contesto in cui il nome di una singola lettera è meglio di un nome più descrittivo. Ma suppongo che questa sia pura opinione.
Jacques B

1
@MilesRout: l'esempio è in realtà per e()contro un nome del metodo auto-documentante . Puoi spiegare in quale contesto è un miglioramento usare nomi di metodi a lettera singola piuttosto che nomi di metodi descrittivi?
Jacques B

6

Regex è come pezzi lego. A prima vista, vedi alcune parti in plastica di forma diversa che possono essere unite. Potresti pensare che non ci sarebbero troppe cose diverse che puoi modellare, ma poi vedi le cose straordinarie che fanno le altre persone e ti chiedi semplicemente quanto sia fantastico un giocattolo.

Regex è come pezzi lego. Ci sono pochi argomenti che possono essere usati, ma concatenarli in forme diverse formerà milioni di diversi schemi regex che possono essere usati per molte attività complicate.

Le persone raramente utilizzavano i parametri regex da soli. Molte lingue offrono funzioni per controllare la lunghezza di una stringa o dividerne le parti numeriche. È possibile utilizzare le funzioni stringa per dividere i testi e riformarli. Il potere di regex si nota quando si utilizzano moduli complessi per eseguire compiti complessi molto specifici.

Puoi trovare decine di migliaia di domande regex su SO e raramente sono contrassegnate come duplicate. Questo da solo mostra i possibili casi d'uso unici che sono molto diversi tra loro.

E non è facile offrire metodi predefiniti per gestire compiti così diversi. Hai funzioni stringa per quel tipo di attività, ma se quelle funzioni non sono sufficienti per l'attività specifica, è tempo di usare regex


2

Riconosco che questo è un problema di pratica piuttosto che di potenza. Il problema si presenta in genere quando le espressioni regolari vengono implementate direttamente , invece di assumere una natura composita. Allo stesso modo, un buon programmatore decompone le funzioni del suo programma in metodi concisi.

Ad esempio, una stringa regex per un URL potrebbe essere ridotta da circa:

UriRe = [scheme][hier-part][query][fragment]

per:

UriRe = UriSchemeRe + UriHierRe + "(/?|/" + UriQueryRe + UriFragRe + ")"
UriSchemeRe = [scheme]
UriHierRe = [hier-part]
UriQueryRe = [query]
UriFragRe = [fragment]

Le espressioni regolari sono cose eleganti, ma sono soggette ad abusi da parte di coloro che si assorbono nella loro apparente complessità. Le espressioni risultanti sono retoriche, assenti di valore a lungo termine.


2
Sfortunatamente la maggior parte dei linguaggi di programmazione non include funzionalità che aiutano a comporre regex e il modo in cui funziona l'acquisizione di gruppo non è molto amichevole con la composizione.
CodesInChaos,

1
Altre lingue devono raggiungere Perl 5 nel loro supporto "espressione regolare compatibile perl". Le sottoespressioni non sono le stesse della semplice concatenazione di stringhe di specifica regex. Le catture dovrebbero essere nominate, non basandosi sulla numerazione implicita.
JDługosz,

0

Come dice @cmaster, le regexps sono state originariamente progettate per essere utilizzate solo al volo ed è semplicemente bizzarro (e leggermente deprimente) che la sintassi del rumore di linea sia ancora la più popolare. Le uniche spiegazioni a cui riesco a pensare riguardano l'inerzia, il masochismo o il machismo (spesso non è l'inerzia la ragione più allettante per fare qualcosa ...)

Perl fa un tentativo piuttosto debole di renderli più leggibili consentendo spazi bianchi e commenti, ma non fa nulla di lontanamente fantasioso.

Esistono altre sintassi. Una buona è la sintassi scsh per regexps , che nella mia esperienza produce regexps che sono ragionevolmente facili da digitare, ma ancora leggibili dopo il fatto.

[ scsh è splendido per altri motivi, solo uno dei quali è il suo famoso testo di riconoscimenti ]


2
Perl6 lo fa! Guarda le grammatiche.
JDługosz,

@ JDługosz Per quanto posso vedere, sembra più un meccanismo per i generatori di parser, piuttosto che una sintassi alternativa per le espressioni regolari. Ma la distinzione forse non è profonda.
Norman Gray,

Può essere un rimpiazzo, ma non si limita alla stessa potenza. È possibile tradurre un regedp in una grammatica in linea con corrispondenza 1 a 1 dei modificatori, ma in una sintassi più leggibile. Esempi che lo promuovono come tali sono nell'apocalisse originale Perl.
JDługosz,

0

Credo che le espressioni regolari siano state progettate per essere il più 'generali' e semplici possibile, quindi possono essere usate (più o meno) allo stesso modo ovunque.

Il tuo esempio regex.isRange(..).followedBy(..)è accoppiato sia alla sintassi di un linguaggio di programmazione specifico sia allo stile orientato agli oggetti (metodo concatenato).

Come sarebbe esattamente questa "regex" in C per esempio? Il codice dovrebbe essere cambiato.

L'approccio più "generale" sarebbe quello di definire un linguaggio semplice e conciso che possa quindi essere facilmente incorporato in qualsiasi altra lingua senza cambiamenti. Ed è (quasi) quello che sono i regex.


0

I motori di espressione regolare compatibili con Perl sono ampiamente utilizzati, fornendo una sintassi concisa delle espressioni regolari che molti editor e lingue comprendono. Come ha sottolineato @ JDługosz nei commenti, Perl 6 (non solo una nuova versione di Perl 5, ma un linguaggio completamente diverso) ha tentato di rendere più leggibili le espressioni regolari costruendole da elementi definiti individualmente. Ad esempio, ecco una grammatica di esempio per l'analisi degli URL da Wikibooks :

grammar URL {
  rule TOP {
    <protocol>'://'<address>
  }
  token protocol {
    'http'|'https'|'ftp'|'file'
  }
  rule address {
    <subdomain>'.'<domain>'.'<tld>
  }
  ...
}

La suddivisione dell'espressione regolare in questo modo consente di definire individualmente ciascun bit (ad es. Il vincolo domaincome alfanumerico) o di estenderlo tramite la sottoclasse (ad es. FileURL is URLChe i vincoli protocoldevono essere solo "file").

Quindi: no, non esiste alcun motivo tecnico per la nervosità delle espressioni regolari, ma i modi più nuovi, più puliti e più leggibili per rappresentarli sono già qui! Quindi speriamo di vedere alcune nuove idee in questo campo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.