Daftar semua karakter khusus yang perlu di-escape dalam regex

108

Saya mencoba membuat aplikasi yang cocok dengan template pesan dengan pesan yang coba dikirim oleh pengguna. Saya menggunakan regex Java untuk mencocokkan pesan. Template / pesan mungkin berisi karakter khusus.

Bagaimana cara mendapatkan daftar lengkap karakter khusus yang perlu di-escape agar regex saya berfungsi dan cocok dalam kasus semaksimal mungkin?

Apakah ada solusi universal untuk meng-escape semua karakter khusus di regex Java?

Avinash Nair
sumber

Jawaban:

94

Anda dapat melihat javadoc dari kelas Pola: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

Anda harus melepaskan karakter apa pun yang terdaftar di sana jika Anda menginginkan karakter biasa dan bukan arti khusus.

Sebagai solusi yang mungkin lebih sederhana, Anda dapat meletakkan template di antara \ Q dan \ E - semua yang ada di antaranya dianggap sebagai escape.

Sorin
sumber
43
Jika Anda merasa \ Q dan \ E sulit diingat, Anda dapat menggunakan Pattern.quote ("...")
mkdev
19
Saya berharap Anda benar-benar menyatakannya
Aleksandr Dubinsky
Mengapa, @AleksandrDubinsky?
Sorin
55
@Sorin Karena itu adalah semangat (bukan, kebijakan?) Stack Exchange untuk menyatakan jawaban dalam jawaban Anda daripada hanya menautkan ke sumber daya di luar situs. Selain itu, halaman itu juga tidak memiliki daftar yang jelas. Daftar dapat ditemukan di sini: docs.oracle.com/javase/tutorial/essential/regex/literals.html , namun menyatakan "Dalam situasi tertentu, karakter khusus yang tercantum di atas tidak akan diperlakukan sebagai karakter meta," tanpa menjelaskan apa yang akan terjadi jika seseorang mencoba melarikan diri dari mereka. Singkatnya, pertanyaan ini layak mendapatkan jawaban yang bagus.
Aleksandr Dubinsky
8
"segala sesuatu di antara mereka [ \Qdan \E] dianggap sebagai lolos" - kecuali yang lain \Qdan \E(yang berpotensi dapat terjadi dalam regex asli). Jadi, lebih baik menggunakan Pattern.quoteseperti yang disarankan di sini dan tidak menciptakan kembali roda.
Sasha
92
  • Karakter Java yang harus di-escape dalam ekspresi reguler adalah:
    \.[]{}()<>*+-=!?^$|
  • Dua tanda kurung tutup ( ]dan }) hanya perlu dilepaskan setelah membuka jenis tanda kurung yang sama.
  • Dalam- []kurung beberapa karakter (seperti +dan -) terkadang bekerja tanpa melarikan diri.
Tobi G.
sumber
Apakah ada cara untuk tidak melarikan diri tetapi mengizinkan karakter itu?
Dominika
1
Melarikan diri dari karakter berarti mengizinkan karakter alih-alih menafsirkannya sebagai operator.
Tobi G.
4
Tidak lolos -dalam []mungkin tidak selalu berfungsi karena digunakan untuk menentukan rentang. Lebih aman untuk menghindarinya. Misalnya pola [-]dan [-)]senar yang cocok -tapi tidak dengan [(-)].
Kenston Choi
1
Meskipun jawaban yang diterima menjawab pertanyaan tersebut, jawaban ini lebih membantu saya ketika saya hanya mencari daftar singkat.
Old Nick
-=!tidak perlu di-escape, itu tergantung pada konteksnya. Misalnya sebagai satu huruf mereka bekerja sebagai ekspresi reguler.
Elang
29

Untuk melarikan diri, Anda bisa menggunakan ini dari Java 1.5 :

Pattern.quote("$test");

Anda akan mencocokkan kata tersebut dengan tepat $test

orang gila
sumber
Mengapa ini bukan jawaban yang berperingkat paling tinggi? Ini memecahkan masalah tanpa masuk ke detail kompleks dari daftar semua karakter yang perlu keluar dan itu bagian dari JDK - tidak perlu menulis kode tambahan! Sederhana!
Volksman
17

Menurut halaman dokumentasi String Literals / Metacharacters , mereka adalah:

<([{\^-=$!|]})?*+.>

Juga akan keren jika daftar itu direferensikan di suatu tempat dalam kode, tetapi saya tidak tahu di mana itu bisa ...

Bohdan
sumber
11
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
marbel82
1
Pola javadoc mengatakan itu adalah kesalahan menggunakan garis miring terbalik sebelum karakter alfabet apa pun yang tidak menunjukkan konstruksi yang diloloskan, tetapi garis miring terbalik dapat digunakan sebelum karakter non-alfabet terlepas dari apakah karakter itu merupakan bagian dari konstruksi yang tidak lolos. Oleh karena itu, regex yang lebih sederhana sudah cukup: di s.replaceAll("[\\W]", "\\\\$0")mana \Wmenunjukkan karakter non-kata.
Joe Bowbeer
6

Menggabungkan apa yang dikatakan semua orang, saya mengusulkan yang berikut ini, untuk menjaga daftar karakter khusus untuk RegExp dengan jelas tercantum dalam String mereka sendiri, dan untuk menghindari keharusan mencoba mengurai ribuan "\\" secara visual. Ini tampaknya bekerja dengan cukup baik untuk saya:

final String regExSpecialChars = "<([{\\^-=$!|]})?*+.>";
final String regExSpecialCharsRE = regExSpecialChars.replaceAll( ".", "\\\\$0");
final Pattern reCharsREP = Pattern.compile( "[" + regExSpecialCharsRE + "]");

String quoteRegExSpecialChars( String s)
{
    Matcher m = reCharsREP.matcher( s);
    return m.replaceAll( "\\\\$0");
}
NeuroDuck
sumber
5

Atas saran @ Sorin tentang dokumen Pola Java, sepertinya karakter yang harus dihindari adalah:

\.[{(*+?^$|
pete
sumber
4
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
fracz
2
)juga harus di-escape, dan bergantung pada apakah Anda berada di dalam atau di luar kelas karakter, mungkin ada lebih banyak karakter untuk di-escape, dalam hal ini Pattern.quotemelakukan pekerjaan yang cukup baik dalam meng-escape string untuk digunakan baik di dalam maupun di luar kelas karakter.
nhahtdh
3

The Pattern.quote(String s)semacam melakukan apa yang Anda inginkan. Namun, hal itu menyisakan sedikit yang diinginkan; itu tidak benar-benar melarikan diri dari karakter individu, hanya membungkus string dengan \Q...\E.

Tidak ada metode yang melakukan persis seperti yang Anda cari, tetapi kabar baiknya adalah sebenarnya cukup mudah untuk melepaskan semua karakter khusus dalam ekspresi reguler Java:

regex.replaceAll("[\\W]", "\\\\$0")

Mengapa ini berhasil? Nah, dokumentasi untuk Patternsecara khusus mengatakan bahwa diperbolehkan untuk keluar dari karakter non-alfabet yang tidak harus di-escape:

Ini adalah kesalahan menggunakan garis miring terbalik sebelum karakter alfabet apa pun yang tidak menunjukkan konstruksi yang lolos; ini disediakan untuk ekstensi mendatang pada bahasa ekspresi reguler. Garis miring terbalik dapat digunakan sebelum karakter non-alfabet terlepas dari apakah karakter tersebut merupakan bagian dari konstruksi yang tidak lolos.

Misalnya, ;bukan karakter khusus dalam ekspresi reguler. Namun, jika Anda menghindarinya, Patternmasih akan diartikan \;sebagai ;. Berikut beberapa contoh lainnya:

  • >menjadi \>yang setara dengan>
  • [menjadi \[yang merupakan bentuk pelarian dari[
  • 8masih 8.
  • \)menjadi \\\)yang merupakan bentuk pelolosan dari \dan (digabungkan.

Catatan: Kuncinya adalah definisi "non-alfabet", yang dalam dokumentasi sebenarnya berarti karakter "non- kata ", atau karakter di luar kumpulan karakter [a-zA-Z_0-9].

wheeler
sumber
2

di sisi lain koin, Anda harus menggunakan regex "non-char" yang terlihat seperti ini jika karakter khusus = allChars - number - ABC - spasi dalam konteks aplikasi Anda.

String regepx = "[^\\s\\w]*";
Bo6Bear
sumber
2

meskipun jawabannya adalah untuk Java, tetapi kodenya dapat dengan mudah diadaptasi dari ekstensi String Kotlin yang saya buat ini (diadaptasi dari @brcolow yang disediakan):

private val escapeChars = charArrayOf(
    '<',
    '(',
    '[',
    '{',
    '\\',
    '^',
    '-',
    '=',
    '$',
    '!',
    '|',
    ']',
    '}',
    ')',
    '?',
    '*',
    '+',
    '.',
    '>'
)

fun String.escapePattern(): String {
    return this.fold("") {
      acc, chr ->
        acc + if (escapeChars.contains(chr)) "\\$chr" else "$chr"
    }
}

fun main() {
    println("(.*)".escapePattern())
}

cetakan \(\.\*\)

periksa aksinya di sini https://pl.kotl.in/h-3mXZkNE

pocesar
sumber
1

Dengan asumsi bahwa Anda memiliki dan mempercayai (untuk menjadi otoritatif) daftar karakter escape yang digunakan Java regex (alangkah baiknya jika karakter ini diekspos di beberapa anggota kelas Pattern), Anda dapat menggunakan metode berikut untuk melarikan diri dari karakter jika memang diperlukan:

private static final char[] escapeChars = { '<', '(', '[', '{', '\\', '^', '-', '=', '$', '!', '|', ']', '}', ')', '?', '*', '+', '.', '>' };

private static String regexEscape(char character) {
    for (char escapeChar : escapeChars) {
        if (character == escapeChar) {
            return "\\" + character;
        }
    }
    return String.valueOf(character);
}
brcolow.dll
sumber