2009-04-11 16 views
8

Ho avuto problemi in Regexes per dividere un codice in componenti funzionali. Possono rompersi o può volerci molto tempo prima che finiscano. L'esperienza solleva una domanda:Quando dovrei usare un parser?

"Quando dovrei usare un parser?"

+0

Non esattamente sicuro se si tratta di un duplicato, ma controllare i seguenti messaggi: * [Quando è un problema troppo complesso per un'espressione regolare?] (Http: // StackOverflow.it/questions/230517/when-is-a-problem-too-complex-for-a-regular-expression) * [Alternative alle espressioni regolari] (http://stackoverflow.com/questions/514313/alternatives-to -regular-expression) – dirkgently

risposta

9

È necessario utilizzare un parser quando si è interessati al significato lessicale o semantica del testo, quando i modelli possono variare. Gli parser sono generalmente esagerati quando stai semplicemente cercando corrispondere o sostituire i modelli di caratteri, indipendentemente dal loro significato funzionale.

Nel tuo caso, sembra che ti interessi il significato del testo ("componenti funzionali" del codice), quindi un parser sarebbe la scelta migliore. Tuttavia, i parser possono utilizzare internamente le regex, quindi non dovrebbero essere considerati come mutuamente esclusivi.


Un "parser" non significa automaticamente che deve essere complicato, tuttavia. Ad esempio, se sei interessato ai blocchi di codice C, potresti semplicemente analizzare i gruppi nidificati di {e}. Questo parser sarebbe interessato solo a due token ('{' e '}') e ai blocchi di testo tra loro.

Tuttavia, un semplice confronto delle espressioni regolari non è sufficiente qui a causa della semantica nidificata. Prendiamo il seguente codice:

void Foo(bool Bar) 
{ 
    if(Bar) 
    { 
     f(); 
    } 
    else 
    { 
     g(); 
    } 
} 

Un parser capirà della portata complessiva Foo, così come ogni portata interna contenuta all'interno Foo (IF ed ELSE). Quando incontra ogni gettone '{', "capisce" il loro significato. Una semplice ricerca, ma non capisce il significato del testo e può interpretare quanto segue per essere un blocco, che noi ovviamente sappiamo non è corretta:

{ 
    if(Bar) 
    { 
     f(); 
    } 
0

La tua domanda è un po 'vago, ma credo che il mio l'opinione è che quando la tua espressione regolare diventa complicata o richiede troppo tempo e tu hai una "lingua" ragionevolmente definita da trattare, un parser sarà più facile.

Non penso che sia possibile impostare una linea nella sabbia e dire che qualsiasi cosa da un lato può essere eseguita tramite regex, e dall'altro lato è necessario un parser. Dipende dalla situazione.

1

È necessario utilizzare un parser non appena si verifica un problema, le espressioni regolari non sono pensate per (o semplicemente non possono) risolvere. Ad esempio, una parentesi (non) bilanciata (in modo ricorsivo) è uno di questi problemi. Anche se alcuni sapori, come PCRE, ti portano molto lontano non riescono a vincere un parser scritto a mano.

2

Esistono alcuni casi di utilizzo convincenti per i parser rispetto alle espressioni regolari. È necessario utilizzare un parser invece di un'espressione regolare:

  • Ogni volta che i tipi di espressioni che desideri lavorare sono più complessi di qualche entità semantiche (tag, le variabili, i numeri di telefono, ecc.)
  • Ogni volta che è necessario conoscere il significato semantico del testo anziché limitarsi a un modello. Ad esempio, se stai cercando di abbinare tutti i modi possibili di scrivere un numero di telefono, un parser è probabilmente meglio di una regex. Se stai cercando di abbinare un modello specifico che corrisponde a un numero di telefono, una regex probabilmente sta bene.
  • Ogni volta che non è possibile garantire che l'input sia ben formato.
  • Se stai lavorando interamente nella struttura di un linguaggio ben definito che ha una specifica di sintassi (C#, XML, C++, Ruby, ecc.), Ci sarà già un parser, quindi hai un po 'di lavoro per te.
+0

+1 per gli esempi concreti. –

+0

@John Feminella, potrei sbagliarmi, ma non sono sicuro di essere d'accordo con l'esempio del numero di telefono. Se vogliamo abbinare vari modi di scrivere un numero di telefono, penso che possa ancora essere ben rappresentato come un'espressione regolare (con una lista opzionale di modelli). Questo potrebbe non essere un ottimo esempio di un caso in cui è necessaria la semantica. – Parag

+0

@Parag: Vorrei avere ancora la pace interiore beata che deriva dal credere che i numeri di telefono possono essere abbinati alle espressioni regolari. I numeri di telefono sono terribilmente complicati da validare pienamente. –

1

Ecco alcuni casi di utilizzo, per gentile concessione di Steve Yegge: Rich Programmer Food.

+0

+1 per il post del blog personale. Ho comprato tre libri su compilatori, ricorrenza e cose simili dopo aver letto =) –

+0

Grazie. In tal caso, dai uno sguardo a: http://stackoverflow.com/questions/725372/which-programming-languages-text –

3

avete bisogno di un parser quando:

  1. lingua non è regolare (wikipedia)
  2. è necessario un albero sintattico (più in generale quando si ha bisogno per eseguire azioni contestualmente)
  3. quando l'espressione regolare risultante è troppo oscuro/complesso

I miei 2 centesimi.

+0

Non intendo fare il nitpick, ma per il punto 1, abbiamo bisogno di un lexer o di un parser? – Parag

2

The Dragon Book ha una piccola sezione di ciò che non è possibile utilizzare le espressioni regolari per:

  • Essi non possono rilevare la ripetizione di una stringa, significa che non è possibile abbinare costrutti come 'wcw', dove w è la stessa successione di simboli
  • È possibile rilevare solo un numero fisso di ripetizioni o un numero imprecisato di ripetizioni, vale a dire che non è possibile utilizzare un token già analizzato per determinare il numero di ripetizioni, ad esempio: 'n s1 s2 ... sn '
  • "Le espressioni regolari non possono essere utilizzate per descrivere costrutti bilanciati o nidificati, [ come] l'insieme di stringhe di tutte le parentesi bilanciati"

Per 1 e 2, c'è una spiegazione semplice, non è possibile catturare una stringa in modo da poter abbinare in un secondo momento. Se lo faresti, allora utilizzeresti un parser. Pensa a come useresti le espressioni regolari per quei casi, e intuitivamente arriverai alla conclusione che non puoi. :)

Per 3, è lo stesso del problema in K & R per l'analisi di stringhe letterali. Non si può semplicemente dire che una stringa letterale è tra il primo "" e il secondo "", ma cosa succede quando c'è una citazione sfuggita (\ ")?

Per quanto riguarda la relazione con il paradosso di Russel, penso il sospetto è giusto, perché il problema sono le limitate capacità di introspezione di regex Il libro ha riferimenti alle dimostrazioni.Se vuoi, posso cercarle per te

+0

Quali sono le premesse per ogni argomento? 1. nessuna inferenza su se stessa 2. poiché la memoria è limitata, i token devono essere finiti 3. tutti - non so perché ma quando ho letto la scrittura ho iniziato a pensare al paradosso di Russell. Puoi ridurre le loro prove ad esso? –

+0

Ho aggiornato la mia risposta. –

+0

@Asdrei Vajna II Si prega di provare a "% s @ \\ (h \\ (el \\) lo \\) @ la stringa è \ 1 e la sottostringa è \ 2 @", quando si ha solo un linea con una parola "ciao". –

0

Ci sono cose che regex non possono fare mentre parser può fare
Ad esempio:.

Inizio :: = (interno);
interno :: = Start | x;

L'espressione regolare non sarebbe in grado di farlo perché la regex non può tracciare se esiste un numero uguale di parentesi aperta e chiusa. Questo è il motivo per cui quando si tenta di eseguire il tokenize e analizzare un file di grandi dimensioni, si prevede che venga utilizzato parser, mentre la regex può semplicemente trovare pattern speciali all'interno del file.

Problemi correlati