2012-05-19 4 views
17

Czy istnieje jakakolwiek metoda w Javie lub dowolnej bibliotece open source, która pozwala na uniknięcie (nie cytowanie) znaku specjalnego (meta-znaku), aby użyć go jako wyrażenia regularnego?Wywoływanie znaków specjalnych w wyrażeniach regularnych Java

Byłoby bardzo przydatny w dynamicznym budowaniu wyrażenia regularnego, bez konieczności ręcznego ucieczki każdego znaku.

Na przykład, rozważmy prosty regex jak \d+\.\d+ pasujący liczby z przecinkiem jak 1.2, jak również następujący kod:

String digit = "d"; 
String point = "."; 
String regex1 = "\\d+\\.\\d+"; 
String regex2 = Pattern.quote(digit + "+" + point + digit + "+"); 

Pattern numbers1 = Pattern.compile(regex1); 
Pattern numbers2 = Pattern.compile(regex2); 

System.out.println("Regex 1: " + regex1); 

if (numbers1.matcher("1.2").matches()) { 
    System.out.println("\tMatch"); 
} else { 
    System.out.println("\tNo match"); 
} 

System.out.println("Regex 2: " + regex2); 

if (numbers2.matcher("1.2").matches()) { 
    System.out.println("\tMatch"); 
} else { 
    System.out.println("\tNo match"); 
} 

Nic dziwnego, że moc wytwarzana przez powyższy kod jest:

Regex 1: \d+\.\d+ 
    Match 
Regex 2: \Qd+.d+\E 
    No match 

Oznacza to, regex1 mecze 1.2 ale regex2 (która jest „dynamicznie” zbudowany) nie (zamiast dopasowuje dosłowne ciąg d+.d+).

A więc, czy istnieje metoda, która automatycznie wymyka się każdemu metatrakowi wyrażenia regularnego?

Gdyby były, powiedzmy, statyczny escape() metodę w java.util.regex.Pattern, wyjście

Pattern.escape('.') 

byłby ciąg "\.", ale

Pattern.escape(',') 

należy po prostu produkować ",", ponieważ jest nie meta-znak. Podobnie

Pattern.escape('d') 

może produkować "\d", ponieważ 'd' jest używany do oznaczenia cyfr (chociaż Cytowanie nie może mieć sens w tym przypadku, jak 'd' może oznaczać dosłowne 'd', który nie będzie niezrozumiany przez interpeter regex być coś innego, jak byłoby w przypadku '.').

+0

Jak taki sposób by określić różnicę beween od 'd' oznaczało jako znak meta i "d" w tekście do dopasowania? ('quote (" d + Dollars? ")' stałoby się '' \\ d + \\ Dollar \\ s? "' w trywialnej metodzie cytowania.) – rsp

+0

Prawidłowo, właśnie dlatego proszę o metodę, która mogłaby uciec indywidualne postacie! :-) – PNS

+0

Aby uciec od pojedynczych znaków, możesz bawić się dopasowując granicę słowa, coś w stylu: 's/\ b ([dswDSW]) \ b/\\ 1/g;' – rsp

Odpowiedz

19

Nie jestem w 100% pewien, że o to pytasz. Jeśli szukasz sposobu, aby stworzyć stałe, które można wykorzystać w swoim regex wzorów wtedy właśnie poprzedzenie ich „\\” będzie działać:

String digit = "\\d"; 

Nie ma Pattern sposób, że wiem, że robi to dla ty. Niestety, chociaż istnieje "\\d" dla cyfr, "\\w" dla znaków roboczych itp. Istnieje również () dla grupowania, + i * dla powtórzeń, itp .. Nie ma typowego sposobu radzenia sobie z każdą częścią wyrażenia regularnego.

W swoim poście używasz Pattern.quote(string) method.Zapewne wiesz, że owija swój wzorzec między "\\Q" i "\\E" dzięki czemu można dopasować ciąg nawet jeśli zdarza się mieć szczególny charakter regex w nim (+, ., \\d, etc.)

+1

Wiem o quote() i jeśli spojrzysz na przykładowe wyjście powyżej zawiera \ Q i \ E. Rzeczywiście, właśnie szukałem metody, która wytworzyłaby zmienioną wersję znaku dla wyrażeń regularnych Java. Na przykład, przecinek z przecinkiem pozostanie przecinkiem, ale okres zanikający powinien stać się \. i tak dalej. – PNS

5

Jedynym sposobem, w jaki regex matcher wie, że szukasz cyfry, a nie litery d, jest uciec przed literą (). Aby wpisać znak escape regex w java, musisz go uciec (aby \ stała się \\). Nie ma więc sposobu na wpisanie podwójnego ukośnika dla specjalnych znaków regex.

+0

Dokładnie, więc chcę metodę, która będzie uciec znak do ciągu regularnego (to znaczy nie literału). – PNS

+0

Można napisać własną metodę 'escape()', która przedrostka '' \\ "' do jej parametru – Attila

+1

Aby być czystym w terminologii, dodanie ukośnika odwrotnego do znaku nie będącego specjalnym nie jest zwane "ucieczką". Aby napisać '\ d' w żaden sposób nie" uciec z litery "' d'. Zamiast tego tworzy całkowicie odrębną koncepcję, klasę znaków, która reprezentuje cyfry. Przykładem ucieczki byłaby twoja druga sprawa, pisząc '\\' do reprezentowania znaku slash. – AndrewF

1

Zgadzam się z Gray, jak ty może potrzebować twojego wzoru, aby mieć zarówno litrale (\ [, \]), jak i meta-znaki ([,]). więc z pewną użytecznością powinieneś być w stanie najpierw uciec przed wszystkimi postaciami, a następnie możesz dodać meta-znaki, które chcesz dodać na tym samym wzorze.

19

pisałem ten wzór:

Pattern SPECIAL_REGEX_CHARS = Pattern.compile("[{}()\\[\\].+*?^$\\\\|]"); 

i używać go w ten sposób:

String escapeSpecialRegexChars(String str) { 

    return SPECIAL_REGEX_CHARS.matcher(str).replaceAll("\\\\$0"); 
} 

Następnie można użyć go w ten sposób, na przykład:

Pattern toSafePattern(String text) 
{ 
    return Pattern.compile(".*" + escapeSpecialRegexChars(text) + ".*"); 
} 

Potrzebowaliśmy aby to zrobić, ponieważ po wyjściu dodajemy wyrazy regularne. Jeśli nie, możesz po prostu użyć \Q i \E:

Pattern toSafePattern(String text) 
{ 
    return Pattern.compile(".*\\Q" + text + "\\E.*") 
} 
+3

Ten nie działał dla mnie (przynajmniej w Scali), ale ten zrobił: '" [\\ {\\} \\ (\\) \\ [\\] \\. \\ + \\ * \\? \\^\\ $ \\\\\\ |] "' – redent84

+0

Istnieje pełna lista specjalnych znaków tutaj: http://stackoverflow.com/a/27454382/1490986 –

0

użytkowania

pattern.compile("\""); 
String s= p.toString()+"yourcontent"+p.toString(); 

dadzą wynik jako yourcontent jak