Cosa fa \? significa in un'espressione regolare?


16

Il seguente comando viene utilizzato per cercare un numero di telefono a 7 cifre:

grep "[[:digit:]]\{3\}[ -]\?[[:digit:]]\{4\}" file

Cosa significa \??

Risposte:


21

È come ?in molti altri motori di espressione regolare, e significa "abbina zero o uno di qualunque cosa sia venuta prima".

Nel tuo esempio, \?viene applicato a [ -], il che significa che cerca di abbinare uno spazio o un segno meno, ma che lo spazio o il segno meno è facoltativo.

Quindi uno di questi corrisponderà:

555 1234
555-1234
5551234

Il motivo è scritto come \?piuttosto che ?per compatibilità con le versioni precedenti.

La versione originale grepusava un diverso tipo di espressione regolare chiamata "espressione regolare di base" dove ?significava solo un punto interrogativo letterale.

Affinché GNU grep potesse avere lo zero o una funzionalità, l'hanno aggiunta, ma ha dovuto usare la \?sintassi in modo che gli script che utilizzavano ?funzionassero ancora come previsto.

Si noti che grep ha -Eun'opzione che lo fa usare il tipo più comune di espressione regolare, chiamato "espressioni regolari estese".

man 1 grep:

   -E, --extended-regexp
          Interpret PATTERN as an extended regular expression
          (ERE, see below).  (-E is specified by POSIX.)

   -G, --basic-regexp
          Interpret PATTERN as a basic regular expression (BRE, see below).
          This is the default.

...

Repetition
    A regular expression may be followed by one of several repetition operators:
    ?      The preceding item is optional and matched at most once.

...

    grep understands three different versions of regular expression syntax:
    “basic,” “extended” and “perl.”

...

Basic vs Extended Regular Expressions
    In basic regular expressions the meta-characters ?, +, {, |, (, and )
    lose their special meaning; instead use the backslashed versions
    \?, \+, \{, \|, \(, and \).

Ulteriori informazioni:


Il egrepcomando è equivalente a grep -E. Per versioni diverse da GNU grep, greppotrebbe o meno accettare l' -Eopzione e egreppotrebbe essere un programma separato.
Keith Thompson,

@KeithThompson, grep -Eè il modo POSIX ufficiale. egrepè stato deprecato in susv2 (1997) e rimosso in susv3 (2001) dalle specifiche POSIX e Unix.
Stéphane Chazelas,

1
\?è un GNUismo però.
Stéphane Chazelas,

8

Sfortunatamente, la sintassi esatta delle espressioni regolari varia leggermente tra i diversi programmi: le regex di grep non sono esattamente le stesse delle regex di sed, che non sono esattamente le stesse delle regex di Emacs, che non sono esattamente le stesse delle regex di C ++, e così su. A peggiorare le cose, anche uno strumento "standard" come grep può variare leggermente tra i diversi sistemi operativi simili a Unix.

In una regex, alcuni personaggi hanno un significato speciale (come le parentesi quadre nel tuo esempio), e ritornano al loro significato normale come caratteri letterali quando li "sfogli" mettendo una barra rovesciata davanti a loro (quindi una parentesi letterale sarebbe scritto come \ [). Altri lavorano al contrario e assumono un significato speciale solo quando sono fuggiti (ad esempio, il semplice n è solo una lettera, ma \ n è un avanzamento riga). E questi, ancora una volta, possono variare tra le implementazioni regex.

Nella maggior parte delle implementazioni regex, un punto interrogativo significa che l'elemento precedente è facoltativo, mentre un punto interrogativo sfuggito (\?) È un punto interrogativo letterale. Ma in alcuni dialetti è il contrario. Il tuo esempio potrebbe avere senso in entrambi i casi, ma sospetto che tu abbia uno dei dialetti dove? è un letterale e \? è il simbolo opzionale. Quindi il tuo regex probabilmente significa "tre cifre, opzionalmente seguite da uno spazio o un trattino, seguite da quattro cifre".

(Un altro indizio può essere visto in costrutti come \ {3 \}, che chiaramente intende significare "esattamente 3 dell'elemento precedente". Nella maggior parte dei dialetti regex questo sarebbe scritto {3} e \ {sarebbe una parentesi letterale .)


6

Questo è un breve riassunto delle informazioni che sono già contenute nelle altre risposte.

In grep, ?corrisponde a un carattere letterale del punto interrogativo e \?indica zero o una ricorrenza di ciò che lo precede. Quindi, nell'esempio nella tua domanda, [ -]\?corrisponde a uno spazio, a un trattino o niente.

In egrepo grep -E, è il contrario; \?corrisponde a un punto interrogativo letterale e ?indica zero o un'occorrenza.

Questo vale per GNU grep; i dettagli per le implementazioni grep non GNU possono differire leggermente. In particolare, greped egreperano storicamente due programmi separati, e non credo che i vecchi grepavessero l' -Eopzione. POSIX specifica grep -E, ma (sono stato sorpreso di scoprire) non menziona egrep.

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.