Apa artinya \? maksud dalam ekspresi reguler?

16

Perintah berikut digunakan untuk mencari nomor telepon 7 digit:

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

Apa artinya \??

pengguna5997
sumber

Jawaban:

21

Ini seperti ?di banyak mesin ekspresi reguler lainnya, dan berarti "cocok dengan nol atau apa pun yang datang sebelumnya".

Dalam contoh Anda, \?diterapkan pada [ -], artinya mencoba mencocokkan ruang atau minus, tetapi ruang atau minus itu opsional.

Jadi semua ini akan cocok:

555 1234
555-1234
5551234

Alasan mengapa ini ditulis \?bukan ?untuk kompatibilitas.

Versi asli dari grepmenggunakan berbagai jenis ekspresi reguler yang disebut "ekspresi reguler dasar" di mana ?hanya berarti tanda tanya literal.

Supaya GNU grep dapat memiliki fungsi nol atau satu, mereka menambahkannya, tetapi harus menggunakan \?sintaks sehingga skrip yang digunakan ?masih berfungsi seperti yang diharapkan.

Perhatikan bahwa grep memiliki -Eopsi yang membuatnya menggunakan jenis ekspresi reguler yang lebih umum, yang disebut "extended regular expressions".

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

Info lebih lanjut:

Mikel
sumber
The egrepperintah setara dengan grep -E. Untuk versi selain GNU grep, grepmungkin atau mungkin tidak menerima -Eopsi, dan egrepmungkin program terpisah.
Keith Thompson
@KeithThompson, grep -Eadalah cara POSIX resmi. egrepdihentikan pada susv2 (1997) dan dihapus pada susv3 (2001) dari spesifikasi POSIX dan Unix.
Stéphane Chazelas
1
\?adalah GNUisme.
Stéphane Chazelas
8

Sayangnya, sintaks yang tepat dari ekspresi reguler bervariasi sedikit antara program yang berbeda: grep regexes tidak persis sama dengan regex sed, yang tidak persis sama dengan regex Emacs, yang tidak persis sama dengan regex C ++, dan sebagainya di. Lebih buruk lagi, bahkan alat "standar" seperti grep dapat sedikit berbeda antara sistem operasi mirip Unix.

Dalam sebuah regex, beberapa karakter memiliki arti khusus (seperti tanda kurung siku dalam contoh Anda), dan kembali ke makna normalnya sebagai karakter literal ketika Anda "melarikan diri" dengan meletakkan garis miring terbalik di depannya (sehingga braket literal akan menjadi ditulis sebagai \ [). Yang lain bekerja sebaliknya, dan hanya mengambil arti khusus ketika lolos (mis. Polos n hanya huruf, tetapi \ n adalah umpan baris). Dan ini, sekali lagi, dapat bervariasi antara implementasi regex.

Di sebagian besar implementasi regex, tanda tanya berarti bahwa item sebelumnya adalah opsional, sedangkan tanda tanya yang lolos (\?) Adalah tanda tanya literal. Tetapi dalam beberapa dialek, itu sebaliknya. Contoh Anda bisa masuk akal, tetapi saya curiga Anda memiliki salah satu dialek di mana? itu literal dan \? adalah simbol opsional. Jadi regex Anda mungkin berarti "tiga digit, opsional diikuti oleh spasi atau tanda hubung, diikuti oleh empat digit".

(Petunjuk lain dapat dilihat dalam konstruksi seperti \ {3 \}, yang jelas dimaksudkan untuk berarti "tepat 3 dari item sebelumnya". Dalam kebanyakan dialek regex ini akan ditulis {3}, dan \ {akan menjadi penjepit literal .)

Ross Smith
sumber
6

Ini adalah ringkasan informasi yang sudah terkandung dalam jawaban lain.

Di grep, ?cocok dengan karakter tanda tanya literal, dan \?menunjukkan nol atau satu kejadian dari apa pun yang mendahuluinya. Jadi, dalam contoh dalam pertanyaan Anda, [ -]\?cocok dengan spasi, atau tanda hubung, atau tidak sama sekali.

Di egrepatau grep -E, itu sebaliknya; \?cocok dengan tanda tanya literal, dan ?menunjukkan nol atau satu kejadian.

Ini berlaku untuk GNU grep; detail untuk implementasi grep non-GNU mungkin sedikit berbeda. Secara khusus, grepdan egrepsecara historis dua program terpisah, dan saya tidak berpikir tua greppunya -Epilihan. POSIX tidak menentukan grep -E, tetapi (saya terkejut menemukan) tidak menyebutkan egrep.

Keith Thompson
sumber