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

我试图使用正则表达式来匹配空格分隔的数字。 我找不到\b的精确定义(“词边界”)。 我假定-12将是一个“整数词”;(由\b\-?\d+\b匹配),但这似乎不起作用。如果能知道…的方法,我将非常感激。

[我在Java 1.6中使用Java正则表达式]

例子:

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
221821 次浏览

我认为它是最后一个匹配或字符串的开始或结束的边界(即字符跟随)。

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

一个可能的选择是

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

这将匹配以空格字符和可选破折号开始,并以单词边界结束的任何数字。它还将匹配从字符串开头开始的数字。

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

因此,在字符串"-12"中,它将匹配在1之前或2之后。破折号不是文字字符。

查看关于边界条件的文档:

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比我先下手为强,所以他得到了支持。

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

  1. 如果第一个字符是单词字符,则在字符串的第一个字符之前。
  2. 如果最后一个字符是单词字符,则在字符串的最后一个字符之后。
  3. 在字符串中的两个字符之间,其中一个是单词字符,另一个不是单词字符。

字字符是字母数字;负号不是。 取自Regex教程.

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

我讨论了__abc0风格的正则表达式边界实际上是在这里

简而言之,它们是有条件的。它们的行为取决于它们旁边的东西。

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


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

有时候这并不是你想要的。详见我的另一个答案。

在搜索诸如.NETC++C#C这样的单词时,我遇到了一个更糟糕的问题。你可能会认为,计算机程序员不会为一种难以编写正则表达式的语言命名。

不管怎样,这是我发现的(主要是从http://www.regular-expressions.info中总结出来的,这是一个很棒的网站):在大多数类型的正则表达式中,由速记字符类\w匹配的字符是被单词边界视为单词字符的字符。Java是个例外。Java支持Unicode的\b,但不支持Unicode的\w。(我敢肯定在当时有一个很好的理由)。

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

然后在你的测试或main函数中:

    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/没有他,正则表达式的世界将是非常悲惨的!

当你使用\\b(\\w+)+\\b时,这意味着与只包含单词字符([a-zA-Z0-9])的单词完全匹配

例如,在regex开头设置\\b将接受-12(带空格),但同样不会接受-12(不带空格)。

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

在学习正则表达式的过程中,我真的被元字符\b困住了。当我反复问自己“这是什么,这是什么”时,我确实没有理解它的意思。在使用该网站进行了一些尝试之后,我在单词的每个开头和单词的末尾注意到粉红色的垂直破折号。当时我很好地理解了它的意思。它现在正好是词(\w)边界

我的观点仅仅是以理解为导向的。其背后的逻辑应该从另一个答案来考察。

enter image description here

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

--?\b\d+\b

检查工作演示

我想解释艾伦·摩尔的回答

字边界是一个位置,它前面有一个字字符而后面没有一个字字符,或者后面有一个字字符而前面没有一个字字符。

假设我有一个字符串&;This is 一个 c一个t, and she's 一个wesome",我想替换所有出现的字母'a',只要这个字母('a')存在于“词的边界”;

换句话说:'cat'中的字母a应该而不是被替换。

因此,我将执行regex(在Python中)为

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

因此,

输入;输出

这是__abc0c__abc0t,她是一个wesome

这是__abc0c_abc1t __abc0d她是__abc0w

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

\b等价于(?<!\w)(?=\w)|(?<=\w)(?!\w)