[regex] 정규식에서 단어 경계는 무엇입니까?

Java 1.6에서 Java 정규식을 사용하고 있으며 (다른 목적 중에서 숫자 출력을 구문 분석하기 위해) \b” 정확한 단어 경계” 의 정확한 정의를 찾을 수 없습니다 . 나는 -12“정수 단어”(와 일치 \b\-?\d+\b) 라고 가정 했지만 이것이 작동하지 않는 것 같습니다. 공백으로 구분 된 숫자를 일치시키는 방법을 알고 감사합니다.

예:

Pattern pattern = Pattern.compile("\\s*\\b\\-?\\d+\\s*");
String plus = " 12 ";
System.out.println(""+pattern.matcher(plus).matches());
String minus = " -12 ";
System.out.println(""+pattern.matcher(minus).matches());
pattern = Pattern.compile("\\s*\\-?\\d+\\s*");
System.out.println(""+pattern.matcher(minus).matches());

이것은 다음을 반환합니다.

true
false
true



답변

단어 경계가 대부분 정규식 방언하는 사이에 위치 인 \w\W그 단어의 문자로 시작하거나 (각각) 끝나는 경우 문자열 (단어가 아닌 문자) 또는 시작 또는 끝 ( [0-9A-Za-z_]).

따라서 문자열 "-12"에서 1 앞뒤에 일치합니다. 대시는 단어 문자가 아닙니다.


답변

단어 경계는 다음 세 위치 중 하나에서 발생할 수 있습니다.

  1. 문자열의 첫 번째 문자 앞에 첫 번째 문자가 단어 문자 인 경우
  2. 문자열의 마지막 문자 다음에 마지막 문자가 단어 문자 인 경우
  3. 문자열에서 두 문자 사이에서 하나는 단어 문자이고 다른 하나는 단어 문자가 아닙니다.

단어 문자는 영숫자입니다. 빼기 부호는 아닙니다. 정규식 튜토리얼 에서 가져 왔습니다 .


답변

정규 표현식을 배우는 과정에서 나는 메타 문자에 정말로 빠져 들었습니다 \b. 나는 ” 그것이 무엇인지, 그것이 무엇인지 반복적 으로 ” 스스로 묻고있는 동안 그 의미를 이해하지 못했습니다 . 웹 사이트 를 사용하여 몇 번 시도한 후 , 나는 단어의 모든 시작과 단어 끝에 분홍색 세로 대시를 보았습니다. 그 당시 그 의미를 잘 알았습니다. 이제 정확하게 단어 \w경계입니다. 입니다.

나의 견해는 단지 엄청나게 이해 지향적 인 것입니다. 그 뒤에 논리는 다른 답변에서 검사해야합니다.

여기에 이미지 설명을 입력하십시오


답변

단어 경계는 단어 문자가 앞에오고 하나가 뒤에 오지 않거나 단어가 뒤에오고 1이 앞에 오지 않는 위치입니다.


답변

나는 \b실제로 어떤 스타일의 정규 표현식 경계 에 대해 이야기 합니다 .

짧은 이야기는 조건부라는 것 입니다. 그들의 행동은 그들이 무엇을하고 있는지에 달려 있습니다.

# same as using a \b before:
(?(?=\w) (?<!\w)  | (?<!\W) )

# same as using a \b after:
(?(?<=\w) (?!\w)  | (?!\W)  )

때때로 그것은 당신이 원하는 것이 아닙니다. 정교화에 대한 다른 답변을 참조하십시오.


답변

Alan Moore 의 답변 을 설명하고 싶습니다

단어 경계는 단어 문자가 앞에 오며 그 뒤에는 하나가 오지 않거나 단어가 뒤에오고 하나가 앞에 오는 위치입니다.

내가 문자열이 “이것은 가정 C t을, 그리고 그녀의 wesome”, 그리고이 모든 사건 (들) 문자 ‘A’이 편지가 존재하는 경우에만 대체 하죠 “단어의 경계” , 즉 ‘고양이’안의 글자 는 교체하지 않아야합니다.a

나는 (에서 정규식 수행 할 수 있습니다 그래서 파이썬 으로)

re.sub("\ba","e", myString.strip())대체 // ae

출력이 될 수 있도록이다 ec를 t 차 그녀의 wesomeee


답변

즉 원하는 텍스트를 검색 할 때 내가 더 악화 문제로 실행 .NET, C++, C#, 및C . 컴퓨터 프로그래머는 정규 표현식을 작성하기 어려운 언어의 이름을 지정하는 것보다 더 잘 알고 있다고 생각합니다.

어쨌든, 이것은 내가 찾은 것입니다 (대부분 훌륭한 사이트 인 http://www.regular-expressions.info 에서 요약 됩니다) : 대부분의 정규 표현식에서 짧은 문자 클래스와 일치하는 문자 \w는 단어 경계에 의해 단어 문자로 취급되는 문자. Java는 예외입니다. Java는 유니 코드를 지원 \b하지만 지원 하지는 않습니다 \w. (당시에는 그만한 이유가 있다고 확신합니다).

\w“단어 문자”를 의미합니다. 항상 ASCII 문자와 일치합니다 [A-Za-z0-9_]. 밑줄과 숫자가 포함되어 있음을 주목하십시오 (단, 대시는 아님). 유니 코드를 지원 \w하는 대부분의 특징에는 다른 스크립트의 많은 문자가 포함됩니다. 어떤 문자가 실제로 포함되는지에 대해 많은 불일치가 있습니다. 알파벳 문자 및 표의 문자와 숫자가 일반적으로 포함됩니다. 밑줄 및 숫자 이외의 숫자 기호 이외의 커넥터 문장 부호는 포함되거나 포함되지 않을 수 있습니다. XML Schema 및 XPath는의 모든 기호를 포함합니다 \w. 그러나 Java, JavaScript 및 PCRE는 ASCII 문자 만와 일치합니다 \w.

대한 정규식 검색을 자바 기반 이유는 C++, C#또는 .NET(당신이 기간 흑자를 탈출 기억 경우에도)에 의해 망했다\b .

참고 : 문장의 끝에 마침표를 쓴 후 누군가가 공백을 넣지 않는 경우와 같이 텍스트의 실수에 대해 어떻게 해야할지 잘 모르겠습니다. 나는 그것을 허용했지만 그것이 반드시 옳은 일인지 확실하지 않습니다.

어쨌든 Java에서 이상한 이름의 언어에 대한 텍스트를 검색하는 경우 \b공백 및 문장 부호 지정 전후 문자 로 대체해야합니다 . 예를 들면 다음과 같습니다.

public static String grep(String regexp, String multiLineStringToSearch) {
    String result = "";
    String[] lines = multiLineStringToSearch.split("\\n");
    Pattern pattern = Pattern.compile(regexp);
    for (String line : lines) {
        Matcher matcher = pattern.matcher(line);
        if (matcher.find()) {
            result = result + "\n" + line;
        }
    }
    return result.trim();
}

그런 다음 테스트 또는 주요 기능에서 :

    String beforeWord = "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|^)";
    String afterWord =  "(\\s|\\.|\\,|\\!|\\?|\\(|\\)|\\'|\\\"|$)";
    text = "Programming in C, (C++) C#, Java, and .NET.";
    System.out.println("text="+text);
    // Here is where Java word boundaries do not work correctly on "cutesy" computer language names.  
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for .NET="+ grep("\\b\\.NET\\b", text));
    System.out.println("Should find: grep exactly for .NET="+ grep(beforeWord+"\\.NET"+afterWord, text));
    System.out.println("Bad word boundary can't find because of Java: grep with word boundary for C#="+ grep("\\bC#\\b", text));
    System.out.println("Should find: grep exactly for C#="+ grep("C#"+afterWord, text));
    System.out.println("Bad word boundary can't find because of Java:grep with word boundary for C++="+ grep("\\bC\\+\\+\\b", text));
    System.out.println("Should find: grep exactly for C++="+ grep(beforeWord+"C\\+\\+"+afterWord, text));

    System.out.println("Should find: grep with word boundary for Java="+ grep("\\bJava\\b", text));
    System.out.println("Should find: grep for case-insensitive java="+ grep("?i)\\bjava\\b", text));
    System.out.println("Should find: grep with word boundary for C="+ grep("\\bC\\b", text));  // Works Ok for this example, but see below
    // Because of the stupid too-short cutsey name, searches find stuff it shouldn't.
    text = "Worked on C&O (Chesapeake and Ohio) Canal when I was younger; more recently developed in Lisp.";
    System.out.println("text="+text);
    System.out.println("Bad word boundary because of C name: grep with word boundary for C="+ grep("\\bC\\b", text));
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));
    // Make sure the first and last cases work OK.

    text = "C is a language that should have been named differently.";
    System.out.println("text="+text);
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

    text = "One language that should have been named differently is C";
    System.out.println("text="+text);
    System.out.println("grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

    //Make sure we don't get false positives
    text = "The letter 'c' can be hard as in Cat, or soft as in Cindy. Computer languages should not require disambiguation (e.g. Ruby, Python vs. Fortran, Hadoop)";
    System.out.println("text="+text);
    System.out.println("Should be blank: grep exactly for C="+ grep(beforeWord+"C"+afterWord, text));

추신 : 정규식 세계가 매우 비참한 http://regexpal.com/에 감사합니다 !