正则表达式中的单词边界是什么?

时间:2009-08-24 20:46:59

标签: regex word-boundary

我在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

13 个答案:

答案 0 :(得分:73)

在大多数正则表达式方言中,单词边界是\w\W(非单词char)之间的位置,或者如果它开始或结束,则位于字符串的开头或结尾处(分别) )带有单词字符([0-9A-Za-z_])。

因此,在字符串"-12"中,它将在1之前或之后匹配。短划线不是单词字符。

答案 1 :(得分:22)

字边界可以出现在以下三个位置之一:

  1. 在字符串中的第一个字符之前,如果第一个字符是单词字符。
  2. 在字符串中的最后一个字符之后,如果最后一个字符是单词字符。
  3. 字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符。
  4. 单词字符是字母数字;减号不是。 取自Regex Tutorial

答案 2 :(得分:11)

单词边界是一个位置,前面是一个单词字符,后面没有一个单词,后面跟一个单词字符,前面没有一个字符。

答案 3 :(得分:6)

我说的是\b样式的正则表达式边界实际上是here

短篇小说是他们有条件的。他们的行为取决于他们的下一步。

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

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

有时候这不是你想要的。请参阅我的其他答案进行详细说明。

答案 4 :(得分: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有点打败我,所以他获得了投票。

答案 5 :(得分:4)

在搜索.NETC++C#C等字词时,我遇到了更糟糕的问题。你会认为计算机程序员比知道一种难以为其编写正则表达式的语言更好。

无论如何,这是我发现的(主要来自http://www.regular-expressions.info,这是一个很棒的网站):在大多数版本的正则表达式中,由短手字符类\w匹配的字符是由字边界视为单词字符的字符。 Java是个例外。 Java支持\b的Unicode,但不支持\w的Unicode。 (我确信当时有充分的理由)。

\w代表“单词字符”。它始终与ASCII字符[A-Za-z0-9_]匹配。请注意包含下划线和数字(但不是破折号!)。在大多数支持Unicode的版本中,\w包含来自其他脚本的许多字符。关于实际包含哪些字符存在很多不一致。通常包括来自字母脚本和表意文字的字母和数字。除了下划线之外的连接符标点和非数字的数字符号可能包括也可能不包括。 XML Schema和XPath甚至包括\w中的所有符号。但是Java,JavaScript和PCRE只匹配带有\w的ASCII字符。

这就是为什么基于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));

P.S。我感谢http://regexpal.com/没有他们的正则表达式世界会非常悲惨!

答案 6 :(得分:3)

在学习正则表达式的过程中,我真的陷入了\b的元字符。当我在重复地问自己“它是什么,它是什么”时,我确实无法理解它的含义。在使用the website进行一些尝试后,我会在每个单词的开头和单词的结尾处注意粉红色的垂直破折号。那个时候我很清楚它的含义。它现在正好是字(\w) - 边界

我的观点仅仅是以理解为导向。应该从另一个答案中检验它背后的逻辑。

enter image description here

答案 7 :(得分:2)

我想解释Alan Moore的答案

  

单词边界是一个位置,该位置或者是一个单词字符的前面而不是一个字符,或者是一个单词字符的后面没有一个字符。

假设我有一个字符串“这是 a c a t,而她的 a 很棒”,我应该替换所有出现的情况(s)仅当字母'a'出现在“单词的边界”(即“猫”内的字母a)上时才替换字母“ a”。

所以我将在

中执行正则表达式(在Python中)

re.sub("\ba","e", myString.strip()) //将a替换为e

所以输出将是 这是 e e ,并且她 e 很棒

答案 8 :(得分:1)

我认为您的问题是由于-不是单词字符。因此,单词边界将在-之后匹配,因此不会捕获它。字符边界在字符串中的第一个字符和最后一个字符之前匹配,以及字符字符或非字符字符之前的任何位置,以及相反之后。另请注意,字边界是零宽度匹配。

一种可能的替代方案是

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

这将匹配以空格字符和可选短划线开头,以字边界结尾的任何数字。它还将匹配从字符串开头开始的数字。

答案 9 :(得分:1)

单词边界\ b用于一个单词应为单词字符而另一个单词应为非单词字符的情况。 负数的正则表达式应为

--?\b\d+\b

检查工作DEMO

答案 10 :(得分:0)

我认为这是最后一场比赛的边界(即跟随字符)或字符串的开头或结尾。

答案 11 :(得分:0)

当您使用\\b(\\w+)+\\b时,表示与仅包含字词([a-zA-Z0-9])的单词完全匹配

在您的情况下,例如在正则表达式开头设置\\b将接受-12(带空格)但又不会接受-12(没有空格)

供参考以支持我的话:https://docs.oracle.com/javase/tutorial/essential/regex/bounds.html

答案 12 :(得分:0)

参考:掌握正则表达式(Jeffrey E.F. Friedl)-O'Reilly

\ b等效于News.objects.filter(category=your_category).order_by("id")