Apa karakter khusus yang harus diloloskan dalam ekspresi reguler?

389

Saya lelah selalu berusaha menebak, jika saya harus melarikan diri karakter khusus seperti ' ()[]{}|' dll ketika menggunakan banyak implementasi regexps.

Ini berbeda dengan, misalnya, Python, sed, grep, awk, Perl, rename, Apache, find, dan sebagainya. Apakah ada aturan yang menentukan kapan saya harus, dan kapan saya tidak boleh, melarikan diri karakter khusus? Apakah itu tergantung pada jenis regexp, seperti PCRE, POSIX atau regexps diperpanjang?

Igor Katson
sumber
4
Perpustakaan regex yang baik memiliki fungsi seperti " escape()" untuk mengizinkan penggunaan string acak sebagai bagian regex.
ivan_pozdeev
2
Anda dapat menggunakan checker ekspresi Regex online seperti gskinner.com/RegExr (gratis). (Ketik, lalu arahkan mouse ke atas regex yang Anda ketikkan)
hexicle
2
Keluar dari semua karakter non-alfanumerik. Titik.
Salman von Abbas
2
Pertanyaan ini telah ditambahkan ke FAQ Ekspresi Reguler Overflow Overflow , di bawah "Lainnya".
aliteralmind
1
Pertanyaan ini telah ditambahkan ke FAQ Ekspresi Reguler Overflow Overflow , di bawah "Escape Sequences".
aliteralmind

Jawaban:

365

Karakter mana yang Anda harus dan yang tidak boleh Anda lepaskan memang tergantung pada rasa regex yang Anda kerjakan.

Untuk PCRE, dan sebagian besar yang disebut rasa yang kompatibel dengan Perl, lepas dari kelas karakter luar ini:

.^$*+?()[{\|

dan kelas-kelas karakter di dalam ini:

^-]\

Untuk POSIX extended regexes (ERE), keluar dari kelas karakter luar ini (sama seperti PCRE):

.^$*+?()[{\|

Melarikan diri dari karakter lain adalah kesalahan dengan POSIX ERE.

Di dalam kelas karakter, garis miring terbalik adalah karakter literal dalam ekspresi reguler POSIX. Anda tidak dapat menggunakannya untuk melarikan diri dari apa pun. Anda harus menggunakan "penempatan pintar" jika Anda ingin memasukkan metakarakter kelas karakter sebagai literal. Letakkan ^ di mana saja kecuali di awal,] di awal, dan - di awal atau di akhir kelas karakter untuk mencocokkan ini secara harfiah, misalnya:

[]^-]

Dalam POSIX basic regular expressions (BRE), ini adalah karakter metak yang perlu Anda hilangkan untuk menekan artinya:

.^$*[\

Melarikan kurung dan kurung keriting di BRE memberi mereka makna khusus yang dimiliki versi yang tidak luput dalam ERE. Beberapa implementasi (mis. GNU) juga memberikan arti khusus untuk karakter lain ketika melarikan diri, seperti \? dan +. Melarikan karakter selain dari. ^ $ * () {} Biasanya merupakan kesalahan dengan BRE.

Di dalam kelas karakter, BRE mengikuti aturan yang sama dengan ERE.

Jika semua ini membuat kepala Anda berputar, ambil salinan RegexBuddy . Pada tab Buat, klik Sisipkan Token, lalu Literal. RegexBuddy akan menambahkan lolos sesuai kebutuhan.

Jan Goyvaerts
sumber
1
Sepertinya Anda Anda lupa "/", yang juga perlu melarikan diri di luar kelas.
jackthehipster
11
/bukan metacharacter dalam salah satu dari rasa ekspresi reguler yang saya sebutkan, jadi sintaks ekspresi reguler tidak mengharuskan untuk menghindarinya. Ketika ekspresi reguler dikutip sebagai literal dalam bahasa pemrograman, maka aturan pemformatan string atau regex dari bahasa tersebut mungkin mengharuskan /atau "atau 'untuk diloloskan, dan bahkan mungkin mengharuskan `\` untuk kabur dua kali.
Jan Goyvaerts
2
bagaimana dengan usus besar, ":"? Haruskah itu lolos di dalam kelas karakter maupun di luar? en.wikipedia.org/wiki/Perl_Compatible_Regular_Expressions mengatakan "PCRE memiliki aturan pelolosan yang konsisten: setiap karakter non-alfa-numerik dapat diloloskan untuk berarti nilai literalnya [...]"
nicolallias
4
MUNGKIN melarikan diri tidak sama dengan HARUS melarikan diri. Sintaks PCRE tidak pernah membutuhkan titik dua untuk diloloskan, jadi keluar dari titik dua hanya membuat regex Anda lebih sulit dibaca.
Jan Goyvaerts
1
Untuk ERE non-POSIX (yang saya gunakan paling sering karena itulah yang diterapkan oleh Tcl) melarikan diri dari hal-hal lain tidak menghasilkan kesalahan.
slebetman
61

Modern RegEx Flavours (PCRE)

Termasuk C, C ++, Delphi, EditPad, Java, JavaScript, Perl, PHP (preg), PostgreSQL, PowerGREP, PowerShell, Python, REALbasic, Studio Asli, Ruby, TCL, VB.Net, VBScript, wxWidgets, XML Schema, Xojo, XRegExp.
Kompatibilitas PCRE dapat bervariasi

    Di mana saja: . ^ $ * + - ? ( ) [ ] { } \ |


Legacy RegEx Flavours (BRE / ERE)

Termasuk awk, ed, egrep, emacs, GNUlib, grep, PHP (ereg), MySQL, Oracle, R, sed.
Dukungan PCRE dapat diaktifkan di versi yang lebih baru atau dengan menggunakan ekstensi

ERE / awk / egrep / emacs

    Di luar kelas karakter: . ^ $ * + ? ( ) [ { } \ |
    Di dalam kelas karakter:^ - [ ]

BRE / ed / grep / sed

    Di luar kelas karakter: . ^ $ * [ \
    Di dalam kelas karakter: ^ - [ ]
    Untuk literal, jangan melarikan diri: + ? ( ) { } |
    Untuk perilaku regex standar, melarikan diri:\+ \? \( \) \{ \} \|


Catatan

  • Jika tidak yakin tentang karakter tertentu, itu bisa lolos seperti \xFF
  • Karakter alfanumerik tidak dapat dihindari dengan backslash
  • Simbol sewenang-wenang dapat melarikan diri dengan backslash di PCRE, tetapi tidak BRE / ERE (mereka hanya harus melarikan diri saat diperlukan). Untuk PCRE ] -hanya perlu melarikan diri dalam kelas karakter, tetapi saya menyimpannya dalam satu daftar untuk kesederhanaan
  • String ungkapan kutip juga harus memiliki karakter kutipan di sekitarnya lolos, dan seringkali dengan garis miring terbalik dua kali lipat (seperti "(\")(/)(\\.)"versus /(")(\/)(\.)/dalam JavaScript)
  • Selain lolos, implementasi regex yang berbeda dapat mendukung berbagai pengubah, kelas karakter, jangkar, kuantifier, dan fitur lainnya. Untuk detail lebih lanjut, lihat regular-expressions.info , atau gunakan regex101.com untuk menguji ekspresi Anda secara langsung
Beejor
sumber
1
Ada banyak kesalahan dalam jawaban Anda, termasuk tetapi tidak terbatas pada: Tidak satu pun dari rasa "modern" Anda yang mengharuskan -atau ]untuk keluar dari kelas karakter. POSIX (BRE / ERE) tidak memiliki karakter pelarian di dalam kelas karakter. Rasa regex dalam RTL Delphi sebenarnya didasarkan pada PCRE. Python, Ruby, dan XML memiliki rasa sendiri yang lebih dekat dengan PCRE daripada rasa POSIX.
Jan Goyvaerts
1
@JanGoyvaerts Terima kasih atas koreksinya. Rasa yang Anda sebutkan memang lebih dekat dengan PCRE. Adapun pelarian, saya menjaga mereka seperti itu untuk kesederhanaan; lebih mudah diingat hanya untuk melarikan diri ke mana-mana daripada beberapa pengecualian. Pengguna yang kuat akan tahu apa yang terjadi, jika mereka ingin menghindari beberapa serangan balik. Lagi pula, saya memperbarui jawaban saya dengan beberapa klarifikasi yang semoga mengatasi beberapa hal ini.
Beejor
22

Sayangnya sebenarnya tidak ada satu set kode pelarian karena bervariasi berdasarkan bahasa yang Anda gunakan.

Namun, menjaga halaman seperti Halaman Alat Ekspresi Reguler atau Lembar Kalimat Ekspresi Reguler ini dapat membantu Anda dengan cepat menyaring berbagai hal.

Dillie-O
sumber
1
Lembar cheat Addedbytes terlalu disederhanakan, dan memiliki beberapa kesalahan mencolok. Sebagai contoh, ia mengatakan \<dan \>merupakan batas kata, yang hanya benar (AFAIK) di perpustakaan peningkatan Boost. Tetapi di tempat lain dikatakan <dan >merupakan metakarakter dan harus melarikan diri (ke \<dan \>) untuk mencocokkannya secara harfiah, yang tidak benar dalam rasa apa pun
Alan Moore
5

Sayangnya, makna hal-hal seperti (dan \ (ditukar antara ekspresi reguler gaya Emacs dan sebagian besar gaya lainnya. Jadi, jika Anda mencoba melarikan diri ini, Anda mungkin melakukan kebalikan dari apa yang Anda inginkan.

Jadi, Anda benar-benar harus tahu gaya apa yang ingin Anda kutip.

Darron
sumber
5

POSIX mengenali banyak variasi pada ekspresi reguler - ekspresi reguler dasar (BRE) dan ekspresi reguler yang diperluas (ERE). Dan bahkan kemudian, ada kebiasaan karena implementasi historis dari utilitas yang distandarisasi oleh POSIX.

Tidak ada aturan sederhana untuk kapan menggunakan notasi mana, atau bahkan notasi mana yang diberikan perintah.

Periksa buku Ekspresi Reguler Reguler Jeff Friedl .

Jonathan Leffler
sumber
4

Sungguh, tidak ada. ada sekitar setengah juta sintaks regex yang berbeda; mereka tampaknya datang ke Perl, EMACS / GNU, dan AT&T secara umum, tapi saya selalu terkejut juga.

Charlie Martin
sumber
4

Terkadang melarikan diri sederhana tidak dimungkinkan dengan karakter yang telah Anda daftarkan. Misalnya, menggunakan garis miring terbalik untuk keluar dari braket tidak akan bekerja di sisi kiri string pengganti dalam sed, yaitu

sed -e 's/foo\(bar/something_else/'

Saya cenderung hanya menggunakan definisi kelas karakter sederhana saja, jadi ungkapan di atas menjadi

sed -e 's/foo[(]bar/something_else/'

yang saya temukan berfungsi untuk sebagian besar implementasi regexp.

Kelas-kelas BTW Character adalah komponen vanilla regexp yang cantik sehingga mereka cenderung bekerja di sebagian besar situasi di mana Anda perlu karakter yang lolos dalam regexps.

Sunting: Setelah komentar di bawah, hanya berpikir saya akan menyebutkan fakta bahwa Anda juga harus mempertimbangkan perbedaan antara automata keadaan terbatas dan automata keadaan tidak terbatas ketika melihat perilaku evaluasi regexp.

Anda mungkin ingin melihat "buku bola mengkilap" alias Efektif Perl ( sanitized Amazon link ), khususnya bab tentang ekspresi reguler, untuk merasakan perbedaan dalam jenis evaluasi mesin regexp.

Tidak semua PCRE di dunia!

Bagaimanapun, regexp sangat kikuk dibandingkan dengan SNOBOL ! Nah , itu kursus pemrograman yang menarik! Seiring dengan yang ada di Simula .

Ah kegembiraan belajar di UNSW di akhir 70-an! (-:

Rob Wells
sumber
'sed' adalah perintah yang polos '(' tidak istimewa tetapi '\ (' khusus; sebaliknya, PCRE membalikkan pengertian, jadi '(' istimewa, tapi '\ (' tidak. Ini persis seperti apa OP bertanya tentang
Jonathan Leffler
sed adalah utilitas * nix yang menggunakan salah satu set evaluasi regexp yang paling primitif. PCRE tidak masuk ke situasi yang saya jelaskan karena melibatkan kelas automata terbatas (in) yang berbeda dengan cara mengevaluasi regexps. Saya pikir saran saya untuk set minimum regexp sintaks masih berlaku.
Rob Wells
1
Pada sistem yang mendukung POSIX, sed menggunakan POSIX BRE, yang saya bahas dalam jawaban saya. Versi GNU pada sistem Linux modern menggunakan POSIX BRE dengan beberapa ekstensi.
Jan Goyvaerts
2

Untuk PHP, "selalu aman untuk mengawali non-alfanumerik dengan" \ "untuk menentukan bahwa itu adalah singkatan dari itu sendiri." - http://php.net/manual/en/regexp.reference.escape.php .

Kecuali jika itu "atau '.: /

Untuk keluar dari variabel pola regex (atau variabel parsial) di PHP, gunakan preg_quote ()

zylstra
sumber
2

Untuk mengetahui kapan dan apa yang harus dihindari tanpa upaya diperlukan untuk memahami dengan tepat rantai konteks yang dilalui oleh string. Anda akan menentukan string dari sisi terjauh ke tujuan akhirnya yang merupakan memori yang ditangani oleh kode parsing regexp.

Waspadai bagaimana string dalam memori diproses: jika bisa berupa string polos di dalam kode, atau string yang dimasukkan ke baris perintah, tetapi bisa berupa baris perintah interaktif atau baris perintah yang dinyatakan di dalam file skrip shell, atau di dalam variabel dalam memori yang disebutkan oleh kode, atau argumen (string) melalui evaluasi lebih lanjut, atau string yang berisi kode yang dihasilkan secara dinamis dengan segala jenis enkapsulasi ...

Masing-masing konteks ini menetapkan beberapa karakter dengan fungsi khusus.

Ketika Anda ingin melewatkan karakter secara harfiah tanpa menggunakan fungsi khusus (lokal ke konteks), maka Anda harus menghindarinya, untuk konteks berikutnya ... yang mungkin memerlukan beberapa karakter pelarian lain yang mungkin juga perlu melarikan diri dalam konteks sebelumnya. Selain itu, ada hal-hal seperti pengkodean karakter (yang paling berbahaya adalah utf-8 karena terlihat seperti ASCII untuk karakter umum, tetapi dapat ditafsirkan secara opsional bahkan oleh terminal tergantung pada pengaturannya sehingga mungkin berperilaku berbeda, kemudian atribut pengkodean HTML / XML, perlu untuk memahami prosesnya dengan tepat.

Misalnya, regexp dalam baris perintah yang dimulai dengan perl -npe, perlu ditransfer ke satu set panggilan sistem exec yang menghubungkan file pipa, masing-masing panggilan sistem exec ini hanya memiliki daftar argumen yang dipisahkan oleh ruang (tidak lolos), dan mungkin pipa (|) dan pengalihan (> N> N> & M), kurung, ekspansi interaktif *dan ?,$(())... (semua ini adalah karakter khusus yang digunakan oleh * sh yang mungkin muncul untuk mengganggu karakter ekspresi reguler dalam konteks berikutnya, tetapi mereka dievaluasi dalam urutan: sebelum baris perintah. Baris perintah dibaca oleh memprogram sebagai bash / sh / csh / tcsh / zsh, pada dasarnya di dalam double quote atau single quote melarikan diri lebih sederhana tetapi tidak perlu untuk mengutip string di baris perintah karena sebagian besar ruang harus diawali dengan backslash dan kutipan tersebut tidak perlu meninggalkan tersedia memperluas fungsi untuk karakter * dan?, tapi ini menguraikan konteks yang berbeda seperti dalam kutipan. Kemudian ketika baris perintah dievaluasi regexp yang diperoleh dalam memori (tidak seperti yang tertulis dalam baris perintah) menerima perlakuan yang sama seperti itu akan berada dalam file sumber. Untuk regexp ada konteks karakter-set dalam tanda kurung [],perl ekspresi reguler dapat dikutip oleh sejumlah besar karakter non-alfa-numerik (Misalnya m // atau m: / better / for / path: ...).

Anda memiliki detail lebih lanjut tentang karakter dalam jawaban lain, yang sangat spesifik untuk konteks regexp akhir. Seperti yang saya catat Anda menyebutkan bahwa Anda menemukan pelarian regexp dengan upaya, itu mungkin karena konteks yang berbeda memiliki serangkaian karakter yang membingungkan memori upaya Anda (sering backslash adalah karakter yang digunakan dalam konteks yang berbeda untuk melarikan diri dari karakter literal alih-alih fungsinya. ).

Marco Munari
sumber
0

Untuk Ionic (Skrip) Anda harus menggandakan garis miring untuk mencetak karakter. Misalnya (ini untuk mencocokkan beberapa karakter khusus):

"^(?=.*[\\]\\[!¡\'=ªº\\-\\_ç@#$%^&*(),;\\.?\":{}|<>\+\\/])"

Perhatikan ] [ - _ . /karakter ini . Mereka harus dipotong ganda. Jika Anda tidak melakukan itu, Anda akan memiliki kesalahan ketik dalam kode Anda.

Alejandro del Río
sumber