Список усіх спеціальних символів, які потрібно уникнути в регулярному виразі


108

Я намагаюся створити додаток, який відповідає шаблону повідомлення та повідомленню, яке користувач намагається надіслати. Я використовую регулярний вираз Java для відповідності повідомлення. Шаблон / повідомлення може містити спеціальні символи.

Як я можу отримати повний перелік спеціальних символів, які потрібно уникнути, щоб мій регекс працював і відповідав максимально можливим випадкам?

Чи є універсальне рішення для втечі від усіх спеціальних символів у Java regex?

Відповіді:


94

Ви можете подивитися javadoc класу Pattern: http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html

Вам потрібно уникнути будь-яких перелічених там знаків, якщо ви хочете звичайного знака, а не особливого значення.

Як, можливо, простіше рішення, ви можете розмістити шаблон між \ Q і \ E - все між ними вважається втеченим.


43
Якщо вам знадобиться \ Q і \ E важко запам'ятати, ви можете використовувати замість Pattern.quote ("...")
— mkdev

19
Я б хотів, щоб ви насправді заявили про них
— Олександр Дубінський,

Чому, @AleksandrDubinsky?
— Сорін

55
@Sorin Тому що це - дух (най, політика?) Біржі стеків, щоб відповісти у своїй відповіді, а не просто посилатися на ресурс поза сайтом. Крім того, на цій сторінці також немає чіткого списку. Зі списком можна ознайомитись тут: docs.oracle.com/javase/tutorial/essential/regex/literals.html , але в ньому зазначено "У певних ситуаціях спеціальні символи, перелічені вище, не розглядаються як метахарактеристики", не пояснюючи, що відбудеться якщо хтось намагається втекти від них. Словом, це запитання заслуговує гарної відповіді.
— Олександр Дубінський,

8
"все між ними [ \Qі \E] вважається втеченим" - за винятком інших \Q"і \E" (що потенційно може статися в оригінальному регулярному вираженні). Отже, краще використовувати, Pattern.quoteяк тут запропоновано, а не винаходити колесо.
— Сашко

92
  • Символи Java, які потрібно уникнути у регулярних виразах:
    \.[]{}()<>*+-=!?^$|
  • Дві із закриваючих дужок ( ]і }) потрібно виключити лише після відкриття однотипного кронштейна.
  • У []дужках деякі символи (як +і -) іноді працюють без уникнення.

Чи є спосіб уникнути, але дозволити цим персонажам?
— Домініка

1
Уникнути символу означає дозволити символу замість інтерпретувати його як оператора.
— Тобі Г.

4
Немальований -в межах []може не завжди працювати, оскільки він використовується для визначення діапазонів. Безпечніше уникати цього. Наприклад, шаблони [-]і [-)]збігаються з рядком, -але не з [(-)].
— Кенстон Чой

1
Незважаючи на те, що прийнята відповідь відповідає на питання, ця відповідь мені була кориснішою, коли я просто шукав швидкий список.
— Старий Нік

-=!не обов’язково уникати, це залежить від контексту. Наприклад, в якості однієї літери вони працюють як постійний регулярний вираз.
— Хоук

29

Щоб уникнути, ви можете просто скористатися цим з Java 1.5 :

Pattern.quote("$test");

Ви точно збіжетеся зі словом $test


Чому це не найвища відповідь? Він вирішує проблему, не вдаючись до складних деталей перерахування всіх символів, які потребують втечі, і це частина JDK - не потрібно писати зайвого коду! Просто!
— Volksman

17

Згідно з документацією на сторінку String Literals / Metacharacters , це:

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

Крім того, було б круто, щоб цей список було проведено десь у коді, але я не знаю, де це могло бути ...


11
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
— marbel82

1
Шаблон javadoc стверджує, що помилка використання зворотної косої риски перед будь-яким алфавітним символом, який не позначає конструкцію, що уникнув, але зворотний косий рядок може бути використаний перед символом, що не буває алфавітом, незалежно від того, чи є цей символ не конструюваною конструкцією. Тому достатньо простішого регулярного вираження: s.replaceAll("[\\W]", "\\\\$0")де \Wпозначаються несловові символи.
— Джо Боубір

6

Поєднуючи те, що всі сказали, пропоную наступне, щоб список символів, спеціальних для RegExp, був чітко переліченим у їх власній строці, а також уникнути необхідності візуального розбору тисяч "\\" 's. Здається, це працює досить добре для мене:

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");
}

5

За пропозицією @ Sorin щодо документів Java Pattern, схоже, що символи для втечі є щонайменше:

\.[{(*+?^$|

4
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
— fracz

2
)також слід уникати, і залежно від того, ви знаходитесь всередині або поза класом символів, для втечі може бути більше символів, і в цьому випадку Pattern.quoteвиконує досить непогану роботу при виведенні рядка для використання як усередині, так і зовні класу символів.
— nhahtdh

3

Вибір Pattern.quote(String s)робить те, що ви хочете. Однак це залишає небагато бажати; насправді це не уникає окремих символів, просто загортає рядок \Q...\E.

Не існує методу, який би робив саме те, що ви шукаєте, але гарна новина полягає в тому, що врятуватись від усіх спеціальних символів у регулярному виразі Java досить просто:

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

Чому це працює? Ну а документація Patternспеціально говорить про те, що допустимо уникати не алфавітних символів, які не обов'язково уникати:

Помилка використання зворотної косої риски перед будь-яким алфавітним символом, який не позначає уникнуту конструкцію; вони зарезервовані для подальшого розширення до мови регулярних виразів. Зворотна косою рисою може бути використана перед символом, що не буває алфавітом, незалежно від того, що цей символ є частиною немальованої конструкції.

Наприклад, ;не є особливим символом у регулярному виразі. Однак, якщо уникнути цього, Patternвсе одно буде тлумачити \;як ;. Ось ще кілька прикладів:

  • >стає тим, \>що еквівалентно>
  • [стає, \[що є втеченою формою[
  • 8є досі 8.
  • \)стає тим, \\\)що є втікаючими формами \і (об'єднаними.

Примітка: Ключ є визначенням «неалфавітних», що в документації на самому ділі означає «не- слово » символи або символи поза набору символів [a-zA-Z_0-9].


2

з іншого боку монети, ви повинні використовувати «нехарактерний» регулярний вираз, який виглядає приблизно так, якщо в контексті програми додаються спеціальні символи = allChars - число - ABC.

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

2

Хоча відповідь стосується Java, але код можна легко адаптувати з цього розширення Kotlin String, яке я придумав (адаптовано з цього @brcolow):

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())
}

відбитки \(\.\*\)

перевірити це в дії тут https://pl.kotl.in/h-3mXZkNE


1

Якщо припустити, що ви маєте довіру (щоб бути авторитетним) переліку символів втечі, який використовує Java-регекс (було б добре, якби ці символи були викриті в якомусь члені класу Pattern), ви можете використовувати наступний метод, щоб уникнути символу, якщо він дійсно необхідний:

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

private static String regexEscape(char character) {
    for (char escapeChar : escapeChars) {
        if (character == escapeChar) {
            return "\\" + character;
        }
    }
    return String.valueOf(character);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.