Quando NON dovresti usare le espressioni regolari? [chiuso]


50

Le espressioni regolari sono un potente strumento nell'arsenale del programmatore, ma - ci sono alcuni casi in cui non sono la scelta migliore o addirittura addirittura dannose.

Il semplice esempio n. 1 è l' analisi dell'HTML con regexp , una strada nota per numerosi bug. Probabilmente, questo attribuisce anche all'analisi in generale.

Ma ci sono altre aree chiaramente vietate per le espressioni regolari?


ps: " La domanda che stai ponendo appare soggettiva ed è probabile che sia chiusa " . Pertanto, voglio sottolineare che sono interessato ad esempi in cui l'uso di regexps è noto per causare problemi.


9
L'analisi dell'HTML con regexp non è solo "una strada nota per numerosi bug". In realtà è impossibile .
Kramii Ripristina Monica il

19
Non solo è impossibile, porta anche alla follia e alla dannazione eterna
Martin Wickman,

3
@Jörg: Regexp è solo un'abbreviazione per l'espressione regolare.
Joren,

3
@Jörg: è vero che esiste una differenza enorme tra le espressioni regolari in matematica e le loro implementazioni nelle librerie di software. È anche vero che la maggior parte delle librerie di espressioni regolari ha estensioni che le collocano ben oltre l'accettazione di semplici linguaggi regolari e che chiamarle espressioni regolari non è sempre così appropriato. Sono d'accordo con te sul fatto che ci sono due concetti diversi. Ma hanno lo stesso nome; regexp è ancora solo un'abbreviazione, non un termine in sé. Molti di questi esempi su questo sito di utilizzo del termine completo per le librerie del software.
Joren,

2
@ Jörg - queste sono semantiche. Mentre può essere una buona idea chiamare questi schemi con nomi diversi (se non altro per evitare l'errore "le espressioni regolari sono per le lingue regolari"), "regexp" / "espressioni regolari" non è un ottimo tentativo, e porta solo a ulteriore confusione.
Kobi,

Risposte:


60

Non usare espressioni regolari:

  • Quando ci sono parser.

Questo non si limita all'HTML . Un semplice XML valido non può essere ragionevolmente analizzato con un'espressione regolare, anche se conosci lo schema e sai che non cambierà mai.

Non provare, ad esempio, ad analizzare il codice sorgente C # . Analizzalo invece, per ottenere una struttura ad albero significativa o i token.

  • Più in generale, quando disponi di strumenti migliori per svolgere il tuo lavoro.

E se dovessi cercare una lettera, sia piccola che maiuscola? Se ami le espressioni regolari, le userai. Ma non è più facile / veloce / leggibile usare due ricerche, una dopo l'altra? Probabilmente nella maggior parte delle lingue otterrai prestazioni migliori e renderai il tuo codice più leggibile.

Ad esempio, il codice di esempio nella risposta di Ingo è un buon esempio quando non è necessario utilizzare espressioni regolari. Cerca foo, quindi bar.

  • Quando analizza la scrittura umana.

Un buon esempio è un filtro di oscenità. Non solo è una cattiva idea in generale implementarla, ma potresti essere tentato di farlo usando espressioni regolari, e sbaglierai. Esistono molti modi in cui un essere umano può scrivere una parola, un numero, una frase e sarà compreso da un altro essere umano, ma non dalla tua espressione regolare. Quindi, invece di catturare la vera oscenità, la tua espressione regolare passerà il suo tempo a fare del male agli altri utenti.

  • Durante la convalida di alcuni tipi di dati.

Ad esempio, non convalidare un indirizzo e-mail tramite un'espressione regolare. Nella maggior parte dei casi, sbaglierai. In un raro caso, lo farai bene e finirai con un horror di codifica di 6 343 caratteri .

Senza gli strumenti giusti, commetterai errori. E li noterai all'ultimo momento, o forse mai. Se non ti interessa il codice pulito, scriverai una stringa di venti righe senza commenti, spazi o righe.

  • Quando verrà letto il tuo codice. E poi leggi ancora, e ancora e ancora, ogni volta da sviluppatori diversi.

Seriamente, se prendo il tuo codice e devo rivederlo o modificarlo, non voglio passare una settimana a cercare di capire una stringa di venti righe di simboli in abbondanza.


9
"Seriamente, se prendo il tuo codice e devo rivederlo o modificarlo, non voglio passare una settimana a cercare di capire una stringa di venti righe di simboli in abbondanza." +1!
funkybro,

1
Questa è una risposta molto migliore della sua sorellastra sullo overflow dello stack: stackoverflow.com/questions/7553722/…
Kobi,

1
Se stai usando Perl / PCRE (e probabilmente anche gli altri moderni sapori regex), leggi le subroutine, i gruppi e le (?(DEFINE))asserzioni nominati ;) Puoi scrivere regex molto puliti usando quelli e in realtà quando li usi scriverai grammatiche che sono molto simile a quello che scriveresti in yacc o simili;)
NikiC

2
L'uso delle espressioni regolari per analizzare le parole nella lista nera è un errore clutturale.
Dan Ray,

Non c'è motivo al mondo per evitare di lanciare una regex su una stringa come "<a href='foo'>stuff</a>". Le regex moderne non hanno problemi con questo.
tchrist

18

La cosa più importante: quando la lingua che stai analizzando non è una lingua normale .

L'HTML non è un linguaggio normale e analizzarlo con un'espressione regolare non è possibile (non solo difficile o una strada per il codice buggy).


4
Sbagliato! Se stai utilizzando uno dei moderni regex flavours (Perl, PCRE, Java, .NET, ...) puoi fare ricorsioni e asserzioni e quindi analizzare anche grammatiche senza contesto e sensibili al contesto.
NikiC

9
@NikiC. Non sbagliato. I "moderni sapori regex" non sono espressioni regolari (che possono essere utilizzate per analizzare le lingue regolari, da cui il nome). Sono d'accordo che con PRE puoi fare di più ma non li definirei solo "espressioni regolari" (come nella domanda originale).
Matteo

1
Le regex moderne sono molto al di là di ciò che è stato insegnato a tua nonna che le regex potrebbero fare che il suo consiglio sia irrilevante. E anche le regex primitive possono gestire la maggior parte dei piccoli frammenti di HTML. Questo divieto generale è ridicolo e non realistico. I regexes sono stati fatti per questo genere di cose. E sì, so di cosa sto parlando .
tchrist

12

Su StackOverflow si vedono spesso persone che chiedono regex per scoprire se una determinata stringa non contiene questo o quello. Questo è, IMHO, invertendo lo scopo dell'espressione regolare. Anche se esiste una soluzione (che utilizza asserzioni negative o simili), spesso è molto meglio usare la regex per quello per cui è stata creata e gestire il caso negativo con la logica del programma.

Esempio:

# bad
if (/complicated regex that assures the string does NOT conatin foo|bar/) {
    # do something
}

# appropriate
if (/foo|bar/) {
    # error handling
} else {
    # do something
}

1
+1: Alcune volte, ho evitato di codificarmi in un angolo con regex fermandomi e chiedendomi "Okay, cosa sto cercando di abbinare in modo specifico?" piuttosto che "Cosa sto cercando di evitare?"

5

Due casi:

Quando c'è un modo più semplice

  • La maggior parte delle lingue fornisce una semplice funzione come INSTR per determinare se una stringa è un sottoinsieme di un'altra. Se è quello che vuoi fare, usa la funzione più semplice. Non scrivere la tua espressione regolare.

  • Se è disponibile una libreria per eseguire una manipolazione di stringhe complesse, utilizzarla anziché scrivere la propria espressione regolare.

Quando le espressioni regolari non sono sufficientemente potenti

  • Se hai bisogno di un parser, usa un parser.

0

Le espressioni regolari non possono identificare strutture ricorsive . Questa è la limitazione fondamentale.

Prendi JSON - è un formato piuttosto semplice, ma poiché un oggetto può contenere altri oggetti come valori membro (arbitrariamente profondi), la sintassi è ricorsiva e non può essere analizzata da una regex. D'altra parte CSV può essere analizzato da regex poiché non contiene alcuna struttura ricorsiva.

In breve, le espressioni regolari non consentono al modello di fare riferimento a se stesso. Non puoi dire: a questo punto nella sintassi abbina di nuovo l'intero modello. Per dirla in altro modo, le espressioni regolari corrispondono solo in modo lineare, non contiene uno stack che gli consentirebbe di tenere traccia di quanto sia profondo un modello nidificato.

Nota che non ha nulla a che fare con la complessità o la complessità del formato. Le espressioni S sono davvero molto semplici, ma non possono essere analizzate con una regex. CSS2 d'altra parte è un linguaggio piuttosto complesso, ma non contiene strutture ricorsive e quindi può essere analizzato con una regex. (Anche se questo non è vero per CSS3 a causa delle espressioni CSS, che hanno una sintassi ricorsiva.)

Quindi non è perché è brutto o complesso o soggetto a errori analizzare HTML usando solo regex. È semplicemente impossibile .

Se è necessario analizzare un formato che contiene strutture ricorsive, è necessario almeno integrare l'uso delle espressioni regolari con uno stack per tenere traccia del livello delle strutture ricorsive. Questo è in genere il modo in cui funziona un parser. Le espressioni regolari vengono utilizzate per riconoscere le parti "lineari", mentre il codice personalizzato esterno al regex viene utilizzato per tenere traccia delle strutture nidificate.

Di solito l'analisi in questo modo viene suddivisa in fasi separate. La tokenizzazione è la prima fase in cui le espressioni regolari vengono utilizzate per dividere l'input in una sequenza di "token" come parole, punteggiatura, parentesi ecc. L'analisi è la fase successiva in cui questi token vengono analizzati in una struttura gerarchica, un albero di sintassi.

Quindi, quando senti che HTML o C # non possono essere analizzati da espressioni regolari, tieni presente che le espressioni regolari sono ancora una parte critica dei parser. Non è possibile analizzare tale linguaggio utilizzando solo espressioni regolari e nessun codice di supporto.

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.