Próbuję utworzyć aplikację, która dopasowuje szablon wiadomości do wiadomości, którą użytkownik próbuje wysłać. Do dopasowania wiadomości używam wyrażenia regularnego Java. Szablon / wiadomość może zawierać znaki specjalne.
Jak uzyskać pełną listę znaków specjalnych, które muszą zostać zmienione, aby moje wyrażenie regularne działało i pasowało w maksymalnych możliwych przypadkach?
Czy istnieje uniwersalne rozwiązanie umożliwiające unikanie wszystkich znaków specjalnych w wyrażeniu regularnym Java?
\Q
i\E
] jest uważane za uciekające” - z wyjątkiem innych\Q
'i\E
' (które potencjalnie mogą wystąpić w oryginalnym wyrażeniu regularnym). Dlatego lepiej jest użyć tego,Pattern.quote
co sugerowano tutaj i nie wymyślać koła na nowo.\.[]{}()<>*+-=!?^$|
]
i}
) należy usunąć dopiero po otwarciu wspornika tego samego typu.[]
nawiasach niektóre znaki (takie jak+
i-
) czasami działają bez ucieczki.źródło
-
w obrębie[]
może nie zawsze działać, ponieważ jest używany do definiowania zakresów. Bezpieczniej jest od tego uciec. Na przykład wzorce[-]
i[-)]
pasują do ciągu,-
ale nie do[(-)]
.-=!
niekoniecznie trzeba uciekać, to zależy od kontekstu. Na przykład jako pojedyncza litera działają jako stałe wyrażenie regularne.Aby uciec, możesz po prostu użyć tego z Java 1.5 :
Dopasujesz dokładnie to słowo
$test
źródło
Według strony dokumentacji String Literals / Metaznaki są to:
<([{\^-=$!|]})?*+.>
Byłoby też fajnie, gdyby ta lista była gdzieś w kodzie, ale nie wiem, gdzie to może być ...
źródło
String escaped = tnk.replaceAll("[\\<\\(\\[\\{\\\\\\^\\-\\=\\$\\!\\|\\]\\}\\)\\?\\*\\+\\.\\>]", "\\\\$0");
s.replaceAll("[\\W]", "\\\\$0")
gdzie\W
oznacza znaki niebędące słowami.Łącząc to, co wszyscy mówili, proponuję co następuje, aby lista znaków specjalnych RegExp była wyraźnie wymieniona w ich własnym łańcuchu znaków i aby uniknąć konieczności wizualnego analizowania tysięcy znaków „\\”. Wydaje mi się, że działa to całkiem nieźle:
źródło
Zgodnie z sugestią @ Sorin dotyczącą dokumentacji Java Pattern, wygląda na to, że znaki, które należy uciec, to co najmniej:
źródło
String escaped = regexString.replaceAll("([\\\\\\.\\[\\{\\(\\*\\+\\?\\^\\$\\|])", "\\\\$1");
)
również musi zostać zmieniony, aw zależności od tego, czy jesteś w klasie znaków, czy poza nią, może być więcej znaków do ucieczki, w takim przypadkuPattern.quote
całkiem dobrze radzi sobie z ucieczką z ciągu do użycia zarówno wewnątrz, jak i na zewnątrz klasy znaków.Pattern.quote(String s)
Rodzaju robi to, co chcesz. Jednak pozostawia trochę do życzenia; w rzeczywistości nie ucieka przed pojedynczymi znakami, po prostu zawija ciąg znaków\Q...\E
.Nie ma metody, która robi dokładnie to, czego szukasz, ale dobrą wiadomością jest to, że w rzeczywistości dość łatwo jest uciec przed wszystkimi znakami specjalnymi w wyrażeniu regularnym Java:
Dlaczego to działa? Cóż, dokumentacja
Pattern
konkretnie mówi, że dozwolone jest unikanie znaków niealfabetycznych, które niekoniecznie muszą być chronione:Na przykład
;
nie jest znakiem specjalnym w wyrażeniu regularnym. Jeśli jednak uciec od tego,Pattern
nadal będzie interpretować\;
jako;
. Oto kilka innych przykładów:>
staje się\>
co jest równoważne z>
[
staje\[
się formą ucieczki[
8
jest nadal8
.\)
staje się tym,\\\)
co uciekło\
i zostało(
połączone.Uwaga: Kluczem jest definicja „niealfabetyczna”, co w dokumentacji tak naprawdę oznacza znaki „inne niż słowo ” lub znaki spoza zestawu znaków
[a-zA-Z_0-9]
.źródło
po drugiej stronie monety powinieneś użyć wyrażenia regularnego „non-char”, które wygląda tak, jeśli znaki specjalne = allChars - number - ABC - space w kontekście twojej aplikacji.
źródło
chociaż odpowiedź dotyczy Javy, ale kod można łatwo zaadaptować z tego rozszerzenia Kotlin String, które wymyśliłem (zaadaptowano z dostarczonego @brcolow):
wydruki
\(\.\*\)
sprawdź to w akcji tutaj https://pl.kotl.in/h-3mXZkNE
źródło
Zakładając, że masz i ufasz (aby być autorytatywnym) listą znaków zmiany znaczenia używanych w wyrażeniach regularnych Java (byłoby miło, gdyby te znaki zostały ujawnione w jakimś elemencie klasy Pattern), możesz użyć następującej metody, aby uniknąć znaku, jeśli jest to rzeczywiście konieczne:
źródło