Java에서 정규식 텍스트를 이스케이프 처리하는 방법


320

Java에는 정규식에 포함될 수 있도록 임의의 텍스트를 이스케이프 처리하는 기본 제공 방법이 있습니까? 예를 들어 사용자가 "$ 5"를 입력하면 입력이 끝난 후 "5"가 아니라 정확하게 일치 시키려고합니다.

답변:


450

이후 자바 1.5, 예 :

Pattern.quote("$5");

88
문자열 자체를 이스케이프 처리하지 않고 \Qand를 사용하여 줄 바꿈하지 마십시오 \E. 예를 위해이 예기치 않은 결과가 발생할 수 있습니다 Pattern.quote("*.wav").replaceAll("*",".*")발생합니다 \Q.*.wav\E하지 .*\.wav예상대로.
Matthias Ronge

11
@Paramaeleon 왜 foo (x) .bar () == x.bar ()를 기대하십니까?
Michael

7
@Paramaeleon 나는 당신이 유스 케이스를 오해하고 있다고 생각합니다.
vikingsteve

18
난 그냥 이스케이프 방식 이스케이프를 나중에 소개하는 식에 적용하는 것을 지적하고 싶습니다 . 놀랍습니다. 당신이 "mouse".toUpperCase().replaceAll("OUS","ic")그것을 반환 MicE합니다. 당신은 반환 할 것으로 예상 would't MICE이 적용되지 않았기 때문에 toUpperCase()ic. 내 예에서는 인서트 quote()에도 적용됩니다 . 다른 일을해야 할 수도 있고 아마도 효과 가 있을 수도 있지만 이는 직관이 아닙니다 . .*replaceAll().replaceAll("*","\\E.*\\Q")
Matthias Ronge

2
이 각각의 탈출을 추가하여 작업을했다 @Paramaleon 경우, 초기 예는 아직도 당신이 원하는 것을하지 않을 것 ... 그것은 개별적으로 문자를 탈출하는 경우, 그것은 될지는 *.wav정규식 패턴으로 \*\.wav, 그리고 완전히 대체하기는으로 바꿀 것 \.*\.wav을 것입니다 의미 이름이 임의의 수의 마침표와 그 뒤에 오는 파일로 구성됩니다 .wav. replaceAll("\\*", ".*")가능한 모든 정규식 charachter를 인식하고 개별적으로 이스케이프 처리하는 좀 더 취약한 구현을 수행 한 경우 가장 필요할 것입니다.
Theodore Murdock 2016 년

112

다음 예를보기 전에 차이점 Pattern.quoteMatcher.quoteReplacement명확하지 않았습니다.

s.replaceFirst(Pattern.quote("text to replace"), 
               Matcher.quoteReplacement("replacement text"));

29
특히, Pattern.quote. | + () 등의 정규식 검색 문자열에서 Matcher.quoteReplacement특수 문자를 대체하고 역 참조를 위해 \ 1과 같은 대체 문자열에서 특수 문자를 대체합니다.
Steven

9
동의하지 않습니다. Pattern.quote는 인수를 \ Q 및 \ E로 래핑합니다. 특수 문자를 이스케이프하지 않습니다.
David Medinets

5
Matcher.quoteReplacement ( "4 $ & % $")는 "4 \ $ & % \ $"를 생성합니다. 특수 문자를 이스케이프합니다.
David Medinets

4
: 말하면 quoteReplacement두 심볼들에 대한 염려 만 $하고 \ , 예를 들면 역 참조로서 대체 문자열에 사용될 수 $1또는 \1. 따라서 정규 표현식을 이스케이프하거나 인용하는 데 사용해서는 안됩니다.
SebastianH

1
대박. 다음은로 바꾸려는 예 $Group$입니다 T$UYO$HI. $기호는 패턴 및 교체에 모두 특별하다 :"$Group$ Members".replaceFirst(Pattern.quote("$Group$"), Matcher.quoteReplacement("T$UYO$HI"))

29

응답하기에는 너무 늦을 수도 있지만 Pattern.LITERAL형식을 지정하는 동안 모든 특수 문자를 무시하는 을 사용할 수도 있습니다 .

Pattern.compile(textToFormat, Pattern.LITERAL);

다음과 결합 할 수 있기 때문에 특히 좋습니다Pattern.CASE_INSENSITIVE
mjjaniec

13

당신이 쫓는 것은 \Q$5\E입니다. Pattern.quote(s)Java5에 도입 된 내용도 참조하십시오 .

세부 사항 은 패턴 javadoc을 참조하십시오.


javadoc이 LITERAL을 켜고 끄는 내장 플래그가 없다고 말했기 때문에 이것과 LITERAL 플래그를 사용하는 것 사이에 차이점이 있는지 궁금합니다. java.sun.com/j2se/1.5.0/docs/api/java/ util / regex /…
Chris Mazzola

15
문자 그대로 \ Q와 \ E를 사용하는 것은 입력을 알고있는 경우에만 좋습니다. Pattern.quote (s)는 텍스트에 실제로 이러한 시퀀스가 ​​포함 된 경우도 처리합니다.
제레미 Huiskamp

10

먼저

  • replaceAll ()을 사용합니다
  • Matcher.quoteReplacement ()를 사용하지 마십시오
  • 대체 될 텍스트는 $ 1을 포함합니다

끝에 1을 넣지 않습니다. 첫 번째 일치 그룹과 하위 THAT에 대한 검색 정규식을 살펴 봅니다. 대체 텍스트에서 $ 1, $ 2 또는 $ 3의 의미는 다음과 같습니다. 검색 패턴에서 일치하는 그룹.

긴 텍스트 문자열을 .properties 파일에 자주 연결 한 다음 전자 메일 제목과 본문을 생성합니다. 실제로 이것은 Spring Framework에서 i18n을 수행하는 기본 방법 인 것으로 보입니다. 자리 표시 자로 XML 태그를 문자열에 넣고 replaceAll ()을 사용하여 XML 태그를 런타임에 값으로 바꿉니다.

사용자가 달러 기호와 함께 달러와 센트 숫자를 입력하는 문제가 발생했습니다. replaceAll ()은 stracktrace에 다음과 같이 표시됩니다.

java.lang.IndexOutOfBoundsException: No group 3
at java.util.regex.Matcher.start(Matcher.java:374)
at java.util.regex.Matcher.appendReplacement(Matcher.java:748)
at java.util.regex.Matcher.replaceAll(Matcher.java:823)
at java.lang.String.replaceAll(String.java:2201)

이 경우 사용자가 입력에 어딘가에 "$ 3"을 입력하고 replaceAll ()이 검색 정규식에서 세 번째 일치 그룹을 찾은 후 찾지 못했습니다.

주어진:

// "msg" is a string from a .properties file, containing "<userInput />" among other tags
// "userInput" is a String containing the user's input

교체

msg = msg.replaceAll("<userInput \\/>", userInput);

msg = msg.replaceAll("<userInput \\/>", Matcher.quoteReplacement(userInput));

문제를 해결했다. 사용자는 문제없이 달러 기호를 포함한 모든 종류의 문자를 넣을 수 있습니다. 예상대로 정확하게 동작합니다.


6

패턴을 보호하기 위해 숫자와 문자를 제외한 모든 기호를 "\\\\"로 바꿀 수 있습니다. 그리고 나서이 보호 된 패턴에 특수 기호를 넣어이 패턴이 어리석은 인용 텍스트가 아니라 실제로 패턴 패턴처럼 작동하도록 만들 수 있습니다. 사용자 특수 기호가 없습니다.

public class Test {
    public static void main(String[] args) {
        String str = "y z (111)";
        String p1 = "x x (111)";
        String p2 = ".* .* \\(111\\)";

        p1 = escapeRE(p1);

        p1 = p1.replace("x", ".*");

        System.out.println( p1 + "-->" + str.matches(p1) ); 
            //.*\ .*\ \(111\)-->true
        System.out.println( p2 + "-->" + str.matches(p2) ); 
            //.* .* \(111\)-->true
    }

    public static String escapeRE(String str) {
        //Pattern escaper = Pattern.compile("([^a-zA-z0-9])");
        //return escaper.matcher(str).replaceAll("\\\\$1");
        return str.replaceAll("([^a-zA-Z0-9])", "\\\\$1");
    }
}

공간을 벗어날 필요는 없습니다. 따라서 패턴을 "([^ a-zA-z0-9])"로 채울 수 있습니다.
Erel Segal-Halevi

5
작은 오타, 큰 결과 : "([^ a-zA-z0-9])"도 탈출하지 않으려는 [, \,], ^와 일치하지 않습니다! 오타는 두 번째 'z'이며 'Z'여야합니다. 그렇지 않으면 ASCII 65에서 ASCII 122까지 모든 것이 포함됩니다.
Zefiro

3

Pattern.quote ( "blabla")가 잘 작동합니다.

Pattern.quote ()가 잘 작동합니다. " \ Q "및 " \ E " 문자로 문장을 묶고 " \ Q "및 " \ E "를 이스케이프하는 경우 문장을 묶습니다 . 그러나 실제 정규 표현식 이스케이프 (또는 사용자 정의 이스케이프)를 수행 해야하는 경우이 코드를 사용할 수 있습니다.

String someText = "Some/s/wText*/,**";
System.out.println(someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));

이 메소드는 다음을 리턴합니다. Some / \ s / wText * / \, **

예제 및 테스트 코드 :

String someText = "Some\\E/s/wText*/,**";
System.out.println("Pattern.quote: "+ Pattern.quote(someText));
System.out.println("Full escape: "+someText.replaceAll("[-\\[\\]{}()*+?.,\\\\\\\\^$|#\\\\s]", "\\\\$0"));

-2

^ (음수) 기호는 문자 그룹에없는 것과 일치하는 데 사용됩니다.

이것은 정규 표현식에 대한 링크입니다

부정에 대한 이미지 정보는 다음과 같습니다.

부정에 대한 정보

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.