GNU/Linux >> Linux Esercitazione >  >> Linux

Perché l'espressione regolare funziona in X ma non in Y?

Ho scritto un'espressione regolare che funziona bene in un determinato programma (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit, ...). Ma quando lo uso in un programma diverso (o su una variante unix diversa), smette di corrispondere. Perché?

Risposta accettata:

Sfortunatamente, per ragioni storiche, strumenti diversi hanno una sintassi delle espressioni regolari leggermente diversa e talvolta alcune implementazioni hanno estensioni che non sono supportate da altri strumenti. Sebbene ci sia un terreno comune, sembra che ogni scrittore di strumenti abbia fatto delle scelte diverse.

La conseguenza è che se si dispone di un'espressione regolare che funziona in uno strumento, potrebbe essere necessario modificarla per funzionare in un altro strumento. Le principali differenze tra gli strumenti comuni sono:

  • se gli operatori +?|(){} richiedono una barra rovesciata;
  • quali estensioni sono supportate oltre alle nozioni di base .[]*^$ e di solito +?|()

In questa risposta, elenco gli standard principali. Controlla la documentazione degli strumenti che stai utilizzando per i dettagli.

Il confronto di Wikipedia sui motori di espressioni regolari ha una tabella che elenca le funzionalità supportate dalle implementazioni comuni.

Espressioni regolari di base (BRE)

Le espressioni regolari di base sono codificate dallo standard POSIX. È la sintassi usata da grep , sed e vi . Questa sintassi fornisce le seguenti caratteristiche:

  • ^ e $ corrisponde solo all'inizio e alla fine di una riga.
  • . corrisponde a qualsiasi carattere (o qualsiasi carattere eccetto una nuova riga).
  • […] corrisponde a qualsiasi carattere elencato tra parentesi (set di caratteri). Se il primo carattere dopo la parentesi aperta è un ^ , vengono invece abbinati i caratteri non elencati. Per includere un ] , inseriscilo subito dopo l'apertura [ (o dopo [^ se è un insieme negativo). Se - è compreso tra due caratteri, denota un intervallo; per includere un letterale - , inseriscilo dove non può essere analizzato come intervallo.
  • Barra rovesciata prima di qualsiasi di ^$.*[ cita il carattere successivo.
  • * corrisponde al carattere o alla sottoespressione precedente 0, 1 o più volte.
  • (…) è un gruppo sintattico, da utilizzare con il * operatore o backreference e DIGIT sostituzioni.
  • Riferimenti precedenti 1 , 2 , … abbina il testo esatto corrispondente al gruppo corrispondente, ad es. (fo*)(ba*)1 corrisponde a foobaafoo ma non foobaafo . Non esiste un modo standard per fare riferimento al 10° gruppo e oltre (il significato standard di 10 è il primo gruppo seguito da un ).

Anche le seguenti funzionalità sono standard, ma mancano in alcune implementazioni limitate:

  • {m,n} corrisponde al carattere o alla sottoespressione precedente tra m a n volte; n o io può essere omesso e {m} significa esattamente m .
  • Tra parentesi si possono usare classi di caratteri, ad esempio [[:alpha:]] corrisponde a qualsiasi lettera. Le moderne implementazioni delle espressioni tra parentesi) includono anche elementi di confronto come [.ll.] e classi di equivalenza come [=a=] .

Le seguenti sono estensioni comuni (specialmente negli strumenti GNU), ma non si trovano in tutte le implementazioni. Consulta il manuale dello strumento che stai utilizzando.

  • | in alternativa:foo|bar corrisponde a foo o bar .
  • ? (abbreviazione di {0,1} ) e + (abbreviazione di {1,} ) corrisponde al carattere o alla sottoespressione precedente al massimo 1 volta, o almeno 1 volta rispettivamente.
  • n corrisponde a una nuova riga, t corrisponde a una scheda, ecc.
  • w corrisponde a qualsiasi componente di una parola (abbreviazione di [_[:alnum:]] ma con variazioni per quanto riguarda la localizzazione) e W corrisponde a qualsiasi carattere che non sia un costituente di una parola.
  • < e > trova la stringa vuota solo all'inizio o alla fine di una parola rispettivamente; b corrisponde a entrambi e B corrisponde a dove b no.

Nota che gli strumenti senza il | operatore non hanno la piena potenza delle espressioni regolari. I backreference consentono alcune cose extra che non possono essere fatte con le espressioni regolari in senso matematico.

Espressioni regolari estese (ERE)

Le espressioni regolari estese sono codificate dallo standard POSIX. Il loro principale vantaggio rispetto a BRE è la regolarità:tutti gli operatori standard sono semplici segni di punteggiatura, una barra rovesciata prima che un carattere di punteggiatura lo citi sempre. È la sintassi usata da awk , grep -E o egrep , GNU sed -r e il =~ di bash operatore. Questa sintassi fornisce le seguenti caratteristiche:

  • ^ e $ corrisponde solo all'inizio e alla fine di una riga.
  • . corrisponde a qualsiasi carattere (o qualsiasi carattere eccetto una nuova riga).
  • […] corrisponde a qualsiasi carattere elencato tra parentesi (set di caratteri). Complementazione con un ^ iniziale e gli intervalli funzionano come in BRE (vedi sopra). Le classi di caratteri possono essere utilizzate ma mancano in alcune implementazioni. Le moderne implementazioni supportano anche classi di equivalenza ed elementi di confronto. Una barra rovesciata tra parentesi cita il carattere successivo in alcune ma non in tutte le implementazioni; usa \ per significare una barra rovesciata per la portabilità.
  • (…) è un gruppo sintattico, da utilizzare con * o DIGIT sostituzioni.
  • | in alternativa:foo|bar corrisponde a foo o bar .
  • * , + e ? corrisponde al carattere o alla sottoespressione precedente un numero di volte:0 o più per * , 1 o più per + , 0 o 1 per ? .
  • La barra rovesciata cita il carattere successivo se non è alfanumerico.
  • {m,n} corrisponde al carattere o alla sottoespressione precedente tra m e n tempi (mancanti da alcune implementazioni); n o io può essere omesso e {m} significa esattamente m .
  • Alcune estensioni comuni come in BRE:DIGIT backreferences (in particolare assenti in awk tranne che nell'implementazione di busybox dove puoi usare $0 ~ "(...)\1" ); caratteri speciali n , t , eccetera.; confini delle parole b e B , costituenti delle parole b e B , …
Correlati:la mia teoria precedente era sbagliata, quindi perché funziona?

PCRE (espressioni regolari compatibili con Perl)

PCRE sono estensioni di ERE, originariamente introdotte da Perl e adottate da GNU grep -P e molti strumenti e linguaggi di programmazione moderni , di solito tramite la libreria PCRE. Vedi la documentazione Perl per una bella formattazione con esempi. Non tutte le funzionalità dell'ultima versione di Perl sono supportate da PCRE (ad es. l'esecuzione di codice Perl è supportata solo in Perl). Consultare il manuale PCRE per un riepilogo delle funzioni supportate. Le principali aggiunte a ERE sono:

  • (?:…) è un gruppo che non cattura:come (…) , ma non conta per i backreference.
  • (?=FOO)BAR (lookahead) corrisponde a BAR , ma solo se esiste anche una corrispondenza per FOO partendo dalla stessa posizione. Questo è molto utile per ancorare una corrispondenza senza includere il seguente testo nella corrispondenza:foo(?=bar) corrisponde a foo ma solo se è seguito da bar .
  • (?!FOO)BAR (lookahead negativo) corrisponde a BAR , ma non c'è nemmeno una corrispondenza per FOO nella stessa posizione. Ad esempio (?!foo)[a-z]+ corrisponde a qualsiasi parola minuscola che non inizia con foo; [a-z]+(?![0-9) corrisponde a qualsiasi parola minuscola che non sia seguita da una cifra (quindi in foo123 , corrisponde a fo ma non foo ).
  • (?<=FOO)BAR (lookbehind) corrisponde a BAR , ma solo se è immediatamente preceduto da una corrispondenza per FOO . FOO deve avere una lunghezza nota (non puoi usare operatori di ripetizione come * ). Questo è molto utile per ancorare una corrispondenza senza includere il testo precedente nella corrispondenza:(?<=^| )foo corrisponde a foo ma solo se è preceduto da uno spazio o dall'inizio della stringa.
  • (?<!FOO)BAR (lookbehind negativo) corrisponde a BAR , ma solo se non è immediatamente preceduto da una corrispondenza per FOO . FOO deve avere una lunghezza nota (non puoi usare operatori di ripetizione come * ). Questo è molto utile per ancorare una corrispondenza senza includere il testo precedente nella corrispondenza:(?<![a-z])foo corrisponde a foo ma solo se non è preceduta da una lettera minuscola.

Emac

La sintassi di Emacs è intermedia tra BRE ed ERE. Oltre a Emacs, è la sintassi predefinita per -regex in GNU trova. Emacs offre i seguenti operatori:

  • ^ , $ , . , […] , * , + , ? come in ERE
  • (…) , | , {…} , DIGIT come in BRE
  • altre sequenze di lettere backslash; < e > per i confini delle parole; e altro nelle versioni recenti di Emacs, che spesso non sono supportate in altri motori con una sintassi simile a Emacs.
Correlati:utilizzare trova per trovare una determinata directory ed eliminare tutti i file in essa contenuti tranne una directory?

Globi di shell

I glob della shell (caratteri jolly) eseguono il pattern matching con una sintassi completamente diversa dalle espressioni regolari e meno potente. Oltre alle shell, questi caratteri jolly sono disponibili con altri strumenti come find -name e filtri di sincronizzazione. I modelli POSIX includono le seguenti caratteristiche:

  • ? corrisponde a qualsiasi singolo carattere.
  • […] è un set di caratteri come nelle comuni sintassi delle espressioni regolari. Alcune shell non supportano le classi di caratteri. Alcune shell richiedono ! invece di ^ per negare l'insieme.
  • * corrisponde a qualsiasi sequenza di caratteri (spesso tranne / quando si abbinano i percorsi dei file; se / è escluso da * , quindi ** a volte include / , ma controlla la documentazione dello strumento).
  • Barra rovesciata cita il carattere successivo.

Ksh offre funzionalità aggiuntive che conferiscono al suo modello la piena potenza delle espressioni regolari. Queste funzionalità sono disponibili anche in bash dopo aver eseguito shopt -s extglob . Zsh ha una sintassi diversa ma può anche supportare la sintassi di ksh dopo setopt ksh_glob .


Linux
  1. Perché la sostituzione del processo Bash non funziona con alcuni comandi?

  2. Perché il file di traduzione Bash non contiene tutti i testi di errore?

  3. Linux – Perché Setuid non funziona??

  4. Linux:perché Locale Es_mx funziona ma non Es?

  5. La definizione di un'espressione regolare?

Perché `zip` in un ciclo For funziona quando il file esiste, ma non quando non lo è?

Perché `esce &` non funziona?

Perché find -exec mv {} ./target/ + non funziona?

Perché la modifica di javascript negli Strumenti per sviluppatori di Chrome non funziona?

La ripetizione automatica non funziona

Perché il bit setuid funziona in modo incoerente?