web-dev-qa-db-ja.com

正規表現の単語境界とは何ですか?

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
98

ほとんどの正規表現方言での単語の境界は、\w\W(非Word文字)の間の位置、または文字列の先頭または末尾(それぞれ)で始まるか終わる場合単語文字([0-9A-Za-z_])。

したがって、文字列"-12"では、1の前または2の後に一致します。ダッシュはWord文字ではありません。

77
brianary

単語の境界は、次の3つの位置のいずれかで発生します。

  1. 文字列の最初の文字の前(最初の文字がWord文字の場合)。
  2. 文字列の最後の文字の後(最後の文字がWord文字の場合)。
  3. 文字列内の2つの文字の間。1つはWord文字で、もう1つはWord文字ではありません。

単語の文字は英数字です。マイナス記号はありません。 Regex Tutorial から取得。

23
WolfmanDragon

単語の境界とは、単語の文字の前に1が付いていない位置、または単語の文字の後に1が付いていない位置です。

11
Alan Moore

\b-スタイルの正規表現の境界が実際に何であるかについて話します ここ

短い話は、彼らが条件付きであるということです。彼らの行動は隣に何があるかによって異なります。

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

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

時々それはあなたが望むものではありません。詳細については、他の回答を参照してください。

7
tchrist

.NETC++C#Cなどの単語をテキストで検索すると、さらに悪い問題に遭遇しました。コンピュータープログラマーは、言語に正規表現を書くのが難しい名前を付けるよりもよく知っていると思うでしょう。

とにかく、これは私が見つけたものです(主に http://www.regular-expressions.info から要約されています、これは素晴らしいサイトです):正規表現のほとんどのフレーバーでは、ショートハンド文字クラス\wは、ワード境界によってワード文字として扱われる文字です。 Javaは例外です。 Javaは\bのUnicodeをサポートしますが、\wのUnicodeはサポートしません。 (当時、それには正当な理由があったと確信しています)。

\wは「単語文字」を表します。常にASCII文字[A-Za-z0-9_]と一致します。アンダースコアと数字が含まれていることに注意してください(ダッシュではありません!)。 Unicodeをサポートするほとんどのフレーバーでは、\wには他のスクリプトからの多くの文字が含まれます。実際にどの文字が含まれているかについては、多くの矛盾があります。通常、アルファベット文字と表意文字の文字と数字が含まれます。アンダースコアと数字以外の数字記号以外のコネクタの句読点は含まれている場合と含まれていない場合があります。 XMLスキーマとXPathには、\wのすべてのシンボルも含まれます。ただし、Java、JavaScript、およびPCREは、ASCII文字と\wのみを照合します。

Javaベースの正規表現が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/ に感謝します。これがないと、正規表現の世界は非常に惨めなものになります。

4
Tihamer

境界条件に関するドキュメントを確認してください。

http://Java.Sun.com/docs/books/tutorial/essential/regex/bounds.html

このサンプルをご覧ください。

public static void main(final String[] args)
    {
        String x = "I found the value -12 in my string.";
        System.err.println(Arrays.toString(x.split("\\b-?\\d+\\b")));
    }

印刷すると、出力は次のようになります。

[文字列に値-が見つかりました。]

これは、「-」文字がWord文字と見なされないため、Wordの境界上にあると見なされないことを意味します。 @brianaryがパンチに打ち勝ったように見えるので、彼は賛成票を獲得します。

4

正規表現を学習する過程で、私は\bというメタキャラクターに本当にこだわっていました。 「それが何であるか、それが何であるか」を繰り返し自問している間、私は確かにその意味を理解していませんでした。 ウェブサイト を使用していくつかの試行を行った後、単語の先頭と末尾にあるピンク色の縦線に注意してください。私はその時にその意味をよく理解しました。現在は正確にWord(\w)-boundaryです。

私の見解は、単に非常に理解志向だということです。その背後にあるロジックは、別の答えから調べる必要があります。

enter image description here

3
snr

アラン・ムーア の答えを説明したいと思います

単語の境界とは、単語の文字の前に1が付いていない位置、または単語の文字の後に1が付いていない位置です。

「これはacatで、彼女はa「素晴らしい」、およびこの文字が「単語の境界」に存在する場合にのみ、文字 'a'のすべての出現を置き換えることになっています。つまり、文字a 「cat」は置き換えないでください。

だから私は正規表現を実行します( Python )として

re.sub("\ba","e", myString.strip()) // aeに置き換えます

出力はこれになりますecat end彼女はewesomeです

3
Dennis

あなたの問題は、-がWordのキャラクターではないという事実によるものだと思います。したがって、Wordの境界は-の後に一致するため、キャプチャされません。単語の境界は、文字列内の最初の単語文字と最後の単語文字の前、およびその前の単語文字または非単語文字、およびその逆の場所と一致します。また、Wordの境界は幅がゼロに一致することに注意してください。

可能な選択肢の1つは

(?:(?:^|\s)-?)\d+\b

これは、スペース文字とオプションのダッシュで始まり、Wordの境界で終わるすべての数字と一致します。また、文字列の先頭から始まる番号にも一致します。

1
Sean

単語境界\ bは、1つの単語がWord文字で、別の単語が非Word文字である場合に使用されます。負の数の正規表現は

--?\b\d+\b

動作確認 DEMO

1
Anubhav Shakya

\\b(\\w+)+\\bを使用すると、Word文字のみを含むWordとの完全一致を意味します([a-zA-Z0-9])

たとえば、正規表現の先頭に\\bを設定すると、-12(スペースあり)が受け入れられますが、-12(スペースなし)は受け入れられません

私の言葉をサポートするための参照: https://docs.Oracle.com/javase/tutorial/essential/regex/bounds.html

0
vic

私はそれが最後の一致の境界(つまり、文字に続く文字列)または文字列の先頭または末尾だと思います。

0
user130076