Co robi \? znaczy w wyrażeniu regularnym?

16

Następujące polecenie służy do wyszukiwania 7-cyfrowego numeru telefonu:

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

Co oznacza \?skrót

użytkownik5997
źródło

Odpowiedzi:

21

Jest tak jak ?w wielu innych silnikach wyrażeń regularnych i oznacza „dopasuj zero lub jeden z tych, które wystąpiły przed nim”.

W twoim przykładzie \?zastosowano do [ -], co oznacza, że ​​próbuje dopasować spację lub minus, ale spacja lub minus są opcjonalne.

Tak więc dowolne z nich będzie pasować:

555 1234
555-1234
5551234

Powodem jest napisane jak \?aniżeli ?jest dla wstecznej kompatybilności.

Oryginalna wersja grepużywała innego rodzaju wyrażenia regularnego zwanego „podstawowym wyrażeniem regularnym”, gdzie ?oznaczało to dosłownie znak zapytania.

Aby GNU grep mógł mieć zero lub jedną funkcjonalność, dodali go, ale musieli użyć \?składni, aby używane skrypty ?działały zgodnie z oczekiwaniami.

Zauważ, że grep ma -Eopcję, która sprawia, że ​​używa bardziej powszechnego typu wyrażeń regularnych, zwanych „rozszerzonymi wyrażeniami regularnymi”.

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 \).

Więcej informacji:

Mikel
źródło
egrepKomenda jest równoważna grep -E. W wersjach innych niż GNU grep grepmoże zaakceptować tę -Eopcję lub może nie egrepbyć osobnym programem.
Keith Thompson,
@KeithThompson, grep -Ejest oficjalnym sposobem POSIX. egrepzostał wycofany w susv2 (1997) i usunięty w susv3 (2001) ze specyfikacji POSIX i Unix.
Stéphane Chazelas,
1
\?jest jednak GNUizmem.
Stéphane Chazelas,
8

Niestety dokładna składnia wyrażeń regularnych różni się nieznacznie w różnych programach: wyrażenia regularne grep nie są dokładnie takie same jak wyrażenia regularne sed, które nie są dokładnie takie same jak wyrażenia regularne Emacsa, które nie są dokładnie takie same jak wyrażenia regularne C ++, i tak na. Co gorsza, nawet „standardowe” narzędzie, takie jak grep, może się nieznacznie różnić w różnych systemach operacyjnych typu Unix.

W wyrażeniu regularnym niektóre znaki mają specjalne znaczenie (takie jak nawiasy kwadratowe w twoim przykładzie) i powracają do normalnego znaczenia jako dosłowne znaki, gdy „uciekasz” przez umieszczenie przed nimi odwrotnego ukośnika (tak więc dosłowny nawias to napisane jako \ [). Inne działają w drugą stronę, a gdy mają znak ucieczki, zyskują specjalne znaczenie (np. Zwykły n to tylko litera, ale \ n to znak wiersza). I te znowu mogą się różnić między implementacjami wyrażeń regularnych.

W większości implementacji wyrażeń regularnych znak zapytania oznacza, że ​​poprzedni element jest opcjonalny, a znak zapytania (\?) To dosłowny znak zapytania. Ale w kilku dialektach jest na odwrót. Twój przykład może mieć sens w obu kierunkach, ale podejrzewam, że masz jeden z dialektów, gdzie? jest dosłowne i \? jest opcjonalnym symbolem. Zatem wyrażenie regularne oznacza prawdopodobnie „trzy cyfry, opcjonalnie po nich spacja lub myślnik, a następnie cztery cyfry”.

(Kolejną wskazówkę można znaleźć w konstrukcjach takich jak \ {3 \}, co wyraźnie ma oznaczać „dokładnie 3 z poprzedniego elementu”. W większości dialektów regularnych byłoby to napisane {3}, a \ {byłoby dosłowne nawias klamrowy .)

Ross Smith
źródło
6

To jest krótkie podsumowanie informacji zawartych już w innych odpowiedziach.

W grep, ?pasuje do dosłownego znak zapytania znak i \?oznacza zero lub jedno wystąpienie jakichkolwiek poprzedza. Zatem w przykładzie w twoim pytaniu [ -]\?pasuje albo spacja, albo łącznik, albo nic.

W egreplub grep -E, jest na odwrót; \?dopasowuje dosłowny znak zapytania i ?oznacza zero lub jedno wystąpienie.

Dotyczy to GNU grep; szczegóły implementacji grep spoza GNU mogą się nieznacznie różnić. W szczególności, grepi egrephistorycznie były to dwa osobne programy, i nie sądzę, aby stare grepmiały taką -Eopcję. POSIX określa grep -E, ale (zaskoczyło mnie odkrycie) nie wspomina egrep.

Keith Thompson
źródło