GNU/Linux >> Belajar Linux >  >> Linux

Mengapa Ekspresi Reguler Bekerja Di X Tapi Tidak Di Y?

Saya menulis ekspresi reguler yang berfungsi dengan baik dalam program tertentu (grep, sed, awk, perl, python, ruby, ksh, bash, zsh, find, emacs, vi, vim, gedit, ...). Tetapi ketika saya menggunakannya di program yang berbeda (atau pada varian unix yang berbeda), itu berhenti cocok. Mengapa?

Jawaban yang Diterima:

Sayangnya, karena alasan historis, alat yang berbeda memiliki sintaks ekspresi reguler yang sedikit berbeda, dan terkadang beberapa implementasi memiliki ekstensi yang tidak didukung oleh alat lain. Meskipun ada kesamaan, sepertinya setiap penulis alat membuat beberapa pilihan yang berbeda.

Konsekuensinya adalah jika Anda memiliki ekspresi reguler yang berfungsi di satu alat, Anda mungkin perlu memodifikasinya agar berfungsi di alat lain. Perbedaan utama antara alat-alat umum adalah:

  • apakah operator +?|(){} memerlukan garis miring terbalik;
  • ekstensi apa yang didukung di luar .[]*^$ dan biasanya +?|()

Dalam jawaban ini, saya mencantumkan standar utama. Periksa dokumentasi alat yang Anda gunakan untuk mengetahui detailnya.

Perbandingan mesin ekspresi reguler Wikipedia memiliki tabel yang mencantumkan fitur yang didukung oleh implementasi umum.

Ekspresi reguler dasar (BRE)

Ekspresi reguler dasar dikodifikasikan oleh standar POSIX. Ini adalah sintaks yang digunakan oleh grep , sed dan vi . Sintaks ini menyediakan fitur berikut:

  • ^ dan $ cocok hanya di awal dan akhir baris.
  • . cocok dengan karakter apa pun (atau karakter apa pun kecuali baris baru).
  • […] cocok dengan salah satu karakter yang tercantum di dalam tanda kurung (set karakter). Jika karakter pertama setelah kurung buka adalah ^ , karakter yang tidak tercantum akan dicocokkan sebagai gantinya. Untuk memasukkan ] , letakkan segera setelah pembukaan [ (atau setelah [^ jika itu adalah himpunan negatif). Jika - berada di antara dua karakter, ini menunjukkan rentang; untuk memasukkan - . literal , letakkan di tempat yang tidak dapat diuraikan sebagai rentang.
  • Garis miring terbalik sebelum ^$.*[ mengutip karakter berikutnya.
  • * cocok dengan karakter atau subekspresi sebelumnya 0, 1 kali atau lebih.
  • (…) adalah grup sintaksis, untuk digunakan dengan * operator atau referensi balik dan DIGIT pengganti.
  • Referensi balik 1 , 2 , … cocok dengan teks yang sama persis dengan grup yang sesuai, mis. (fo*)(ba*)1 cocok dengan foobaafoo tapi bukan foobaafo . Tidak ada cara standar untuk merujuk ke grup ke-10 dan seterusnya (arti standar 10 adalah grup pertama diikuti oleh < ).

Fitur berikut juga standar, tetapi tidak ada dalam beberapa penerapan terbatas:

  • {m,n} cocok dengan karakter atau subekspresi sebelumnya antara m ke n waktu; n atau m dapat dihilangkan, dan {m} berarti persis m .
  • Di dalam kurung, kelas karakter dapat digunakan, misalnya [[:alpha:]] cocok dengan huruf apa pun. Implementasi modern dari ekspresi tanda kurung) juga menyertakan elemen susunan seperti [.ll.] dan kelas kesetaraan seperti [=a=] .

Berikut ini adalah ekstensi umum (terutama di alat GNU), tetapi tidak ditemukan di semua implementasi. Periksa manual alat yang Anda gunakan.

  • | untuk pergantian:foo|bar cocok dengan foo atau bar .
  • ? (kependekan dari {0,1} ) dan + (kependekan dari {1,} ) cocok dengan karakter atau subekspresi sebelumnya paling banyak 1 kali, atau setidaknya 1 kali berturut-turut.
  • n cocok dengan baris baru, t cocok dengan tab, dll.
  • w cocok dengan konstituen kata apa pun (kependekan dari [_[:alnum:]] tetapi dengan variasi dalam hal pelokalan) dan W cocok dengan karakter apa pun yang bukan merupakan konstituen kata.
  • < dan > mencocokkan string kosong masing-masing hanya di awal atau akhir kata; b cocok, dan B cocok dengan b tidak.

Perhatikan bahwa alat tanpa | operator tidak memiliki kekuatan penuh ekspresi reguler. Referensi balik memungkinkan beberapa hal tambahan yang tidak dapat dilakukan dengan ekspresi reguler dalam arti matematika.

Extended Regular Expression (ERE)

Ekspresi reguler yang diperluas dikodifikasikan oleh standar POSIX. Keuntungan utama mereka atas BRE adalah keteraturan:semua operator standar adalah karakter tanda baca kosong, garis miring terbalik sebelum karakter tanda baca selalu mengutipnya. Ini adalah sintaks yang digunakan oleh awk , grep -E atau egrep , GNU sed -r , dan bash's =~ operator. Sintaks ini menyediakan fitur berikut:

  • ^ dan $ cocok hanya di awal dan akhir baris.
  • . cocok dengan karakter apa pun (atau karakter apa pun kecuali baris baru).
  • […] cocok dengan salah satu karakter yang tercantum di dalam tanda kurung (set karakter). Komplementasi dengan ^ initial inisial dan rentang berfungsi seperti di BRE (lihat di atas). Kelas karakter dapat digunakan tetapi hilang dari beberapa implementasi. Implementasi modern juga mendukung kelas kesetaraan dan elemen penyusunan. Garis miring terbalik di dalam tanda kurung mengutip karakter berikutnya di beberapa tetapi tidak semua implementasi; gunakan \ berarti garis miring terbalik untuk portabilitas.
  • (…) adalah grup sintaksis, untuk digunakan dengan * atau DIGIT pengganti.
  • | untuk pergantian:foo|bar cocok dengan foo atau bar .
  • * , + dan ? cocok dengan karakter atau subekspresi sebelumnya beberapa kali:0 atau lebih untuk * , 1 atau lebih untuk + , 0 atau 1 untuk ? .
  • Backslash mengutip karakter berikutnya jika bukan alfanumerik.
  • {m,n} cocok dengan karakter atau subekspresi sebelumnya antara m dan n kali (hilang dari beberapa implementasi); n atau m dapat dihilangkan, dan {m} berarti persis m .
  • Beberapa ekstensi umum seperti pada BRE:DIGIT backreferences (terutama tidak ada dalam awk kecuali dalam implementasi busybox di mana Anda dapat menggunakan $0 ~ "(...)\1" ); karakter khusus n , t , dll.; batas kata b dan B , konstituen kata b dan B , …
Terkait:Teori saya sebelumnya salah, jadi mengapa ini berhasil?

PCRE (ekspresi reguler yang kompatibel dengan Perl)

PCRE adalah ekstensi dari ERE, awalnya diperkenalkan oleh Perl dan diadopsi oleh GNU grep -P dan banyak alat dan bahasa pemrograman modern , biasanya melalui perpustakaan PCRE. Lihat dokumentasi Perl untuk pemformatan yang bagus dengan contoh. Tidak semua fitur Perl versi terbaru didukung oleh PCRE (mis. Eksekusi kode Perl hanya didukung di Perl). Lihat manual PCRE untuk ringkasan fitur yang didukung. Tambahan utama untuk ERE adalah:

  • (?:…) adalah grup yang tidak menangkap:seperti (…) , tetapi tidak dihitung sebagai referensi balik.
  • (?=FOO)BAR (lookahead) cocok dengan BAR , tetapi hanya jika ada kecocokan untuk FOO mulai dari posisi yang sama. Ini paling berguna untuk mengaitkan kecocokan tanpa menyertakan teks berikut dalam kecocokan:foo(?=bar) cocok dengan foo tetapi hanya jika diikuti oleh bar .
  • (?!FOO)BAR (lookahead negatif) cocok dengan BAR , tetapi tidak ada kecocokan untuk FOO pada posisi yang sama. Misalnya (?!foo)[a-z]+ cocok dengan kata kecil apa pun yang tidak dimulai dengan foo; [a-z]+(?![0-9) cocok dengan kata kecil apa pun yang tidak diikuti oleh angka (jadi di foo123 , cocok dengan fo tapi bukan foo ).
  • (?<=FOO)BAR (lihat ke belakang) cocok dengan BAR , tetapi hanya jika itu segera didahului oleh kecocokan untuk FOO . FOO harus memiliki panjang yang diketahui (Anda tidak dapat menggunakan operator pengulangan seperti * ). Ini paling berguna untuk mengaitkan kecocokan tanpa menyertakan teks sebelumnya dalam kecocokan:(?<=^| )foo cocok dengan foo tetapi hanya jika diawali dengan spasi atau awal string.
  • (?<!FOO)BAR (lihat negatif ke belakang) cocok dengan BAR , tetapi hanya jika tidak segera didahului oleh kecocokan untuk FOO . FOO harus memiliki panjang yang diketahui (Anda tidak dapat menggunakan operator pengulangan seperti * ). Ini paling berguna untuk mengaitkan kecocokan tanpa menyertakan teks sebelumnya dalam kecocokan:(?<![a-z])foo cocok dengan foo tetapi hanya jika tidak didahului dengan huruf kecil.

Emacs

Sintaks Emacs adalah perantara antara BRE dan ERE. Selain Emacs, ini adalah sintaks default untuk -regex di GNU temukan. Emacs menawarkan operator berikut:

  • ^ , $ , . , […] , * , + , ? seperti di ERE
  • (…) , | , {…} , DIGIT seperti di BRE
  • lebih banyak urutan huruf miring terbalik; < dan > untuk batas kata; dan lebih banyak lagi di versi terbaru Emacs, yang sering kali tidak didukung di mesin lain dengan sintaks mirip Emacs.
Terkait:Gunakan find untuk menemukan direktori tertentu dan menghapus semua file di dalamnya kecuali satu direktori?

Gumpalan cangkang

Gumpalan shell (wildcard) melakukan pencocokan pola dengan sintaks yang benar-benar berbeda dari ekspresi reguler dan kurang kuat. Selain shell, wildcard ini tersedia dengan alat lain seperti find -name dan filter rsync. Pola POSIX mencakup fitur berikut:

  • ? cocok dengan satu karakter apa pun.
  • […] adalah kumpulan karakter seperti pada sintaks ekspresi reguler umum. Beberapa shell tidak mendukung kelas karakter. Beberapa shell membutuhkan ! bukannya ^ untuk meniadakan himpunan.
  • * cocok dengan urutan karakter apa pun (seringkali kecuali / saat mencocokkan jalur file; jika / dikecualikan dari * , lalu ** terkadang menyertakan / , tetapi periksa dokumentasi alat).
  • Backslash mengutip karakter berikutnya.

Ksh menawarkan fitur tambahan yang memberikan polanya yang cocok dengan kekuatan penuh ekspresi reguler. Fitur-fitur ini juga tersedia di bash setelah menjalankan shopt -s extglob . Zsh memiliki sintaks yang berbeda tetapi juga dapat mendukung sintaks ksh setelah setopt ksh_glob .


Linux
  1. Mengapa File Terjemahan Bash Tidak Berisi Semua Teks Kesalahan?

  2. Linux – Mengapa Setuid Tidak Bekerja??

  3. Linux – Mengapa Es_mx Lokal Bekerja Tapi Tidak Es?

  1. Mengapa `zip` Dalam A For Loop Bekerja Saat File Ada, Tapi Tidak Saat Tidak?

  2. Mengapa Dokumen Induk Shell Di Sini Tidak Berfungsi Untuk Sub-perintah Di Dash Tapi Bash Bekerja?

  3. Mengapa "sementara Baca" Ini Bekerja Di Terminal, Tapi Tidak Di Skrip Shell?

  1. Mengapa find -exec mv {} ./target/ + tidak berfungsi?

  2. wc -l TIDAK menghitung file terakhir jika tidak memiliki karakter baris akhir

  3. Mengapa mengedit javascript di Alat Pengembang Chrome tidak berfungsi?