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


137

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

入力と期待される出力を含む小さな例を投稿できますか?
ブレントがコード

例パターンパターン= Pattern.compile( "\\ s * \\ b \\-?\\ d + \\ s *"); 文字列プラス= "12"; System.out.println( "" + pattern.matcher(plus).matches()); 文字列マイナス= "-12"; System.out.println( "" + pattern.matcher(minus).matches()); pattern = Pattern.compile( "\\ s * \\-?\\ d + \\ s *"); System.out.println( "" + pattern.matcher(minus).matches()); 与える:true false true
peter.murray.rust

回答:


97

単語境界は、ほとんどの正規表現の方言で、\wand \W(非単語文字)の間の位置、または(それぞれ)単語文字([0-9A-Za-z_])で開始または終了する場合は文字列の最初または最後にあります。

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


35
Correctamundo。\b幅がゼロのアサーションであり\w、片側にあり\W、もう一方にあるか、位置が文字列の先頭または末尾である場合に一致します。\w「識別子」の文字(数字とアンダースコア)として任意に定義され、英語で特に役立つものではありません。
ホッブズ

100%正解です。自分についてコメントするだけでなく、謝罪します。私はあなたの答えを見る前に送信を押しました。
ブレントがコードを作成

5
理解のために、それは正規表現を書き換えることが可能である\bhello\b使用せずに\b(使用\w\Wおよび他の)?
David Portabella、2016

5
並べ替え:(^|\W)hello($|\W)。ただし、前後の単語以外の文字はキャプチャされないため、より(^|(?<=\W))hello($|(?=\W))先読みになります(先読み/後読みアサーションを使用)。
ブライアリー2016

6
@brianary少しシンプルに:(?<!\w)hello(?!\w)
David Knipe 2017年

28

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

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

単語の文字は英数字です。マイナス記号はそうではありません。正規表現チュートリアルから取得


21

正規表現を学習する過程で、私は本当にメタキャラクターに悩まされていました\b。「それが何であるか、何であるか」を繰り返し問いかけている間、私は実際にその意味を理解しませんでした。ウェブサイトを使用しいくつかの試みを行った後、単語の最初と最後にピンクの縦線が表示されているのを確認しました。当時はその意味がよく分かりました。これは正確にword(\w)-boundaryですです。

私の見解は、非常に理解を重視することです。その背後にある論理は別の答えから検討する必要があります。

ここに画像の説明を入力してください


3
単語の境界とは何か、どのようにして一致が発生しているのかを理解するのに非常に良いサイト
vsingh

2
この投稿は、伝えるのではなく表示するための信用に値します。絵は千の言葉に値する。
M_M

13

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


8

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

ショートストーリーは、条件付きであることです。彼らの行動は彼らが隣にいるものに依存します。

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

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

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


7

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

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

「これは私が、文字列があるとし、C 、T、そして彼女はだ「」この手紙がで存在する場合にのみ、文字wesome」、と私はすべてのオカレンス(複数可)を置き換えることになっています「という単語の境界」、すなわち手紙a「猫」の中の置き換えないでください。

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

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

出力がされますので、これがあるecのT ndは彼女のwesomeee


5

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

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

\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));

PS http://regexpal.com/に感謝します。これがないと、正規表現の世界は非常に悲惨です。


なぜ一致しなかったのか理解するのに苦労しましたC#が、今では
もっと

4

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

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")));
    }

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

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

これは、「-」文字は単語の文字と見なされないため、単語の境界にあるものとしてピックアップされないことを意味します。@brianaryが私にパンチを打ち負かしたようなので、彼は賛成票を獲得しました。


2

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

--?\b\d+\b

動作しているデモを確認する


1

私はあなたの問題は-単語の文字ではないという事実が原因であると信じています。したがって、単語の境界はの後に一致-するため、キャプチャされません。単語の境界は、文字列内の最初と最後の単語文字の前、および単語文字または非単語文字の前、およびその反対の場所と一致します。また、ワード境界は幅がゼロの一致であることに注意してください。

1つの可能な代替策は

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

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


0

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


1
あなたは考えています\G\A最初の一致の試みで文字列の先頭(のような)に一致します。その後、前の試合が終了した位置と一致します。
Alan Moore

0

使用\\b(\\w+)+\\bすると、単語文字のみを含む単語と完全に一致することになります([a-zA-Z0-9])

あなたの場合、例えば\\b正規表現の最初の設定は受け入れます-12(スペースあり)が、再び受け入れません-12(スペースなし)

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.