我在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
(非单词char)之间的位置,或者如果它开始或结束(分别)带有单词字符([0-9A-Za-z_]
),则位于字符串的开头或结尾。
因此,在字符串"-12"
中,它将在1之前或之后匹配。短划线不是单词字符。
我认为它是最后一个匹配的边界(即字符跟随)或字符串的开头或结尾。
当你使用\\b(\\w+)+\\b
时,这意味着与仅包含单词字符([a-zA-Z0-9])
的单词完全匹配
在你的情况下,例如在正则表达式的开头设置qazxsw poi将接受qazxsw poi(带空格)但是它再次不接受\\b
(没有空格)
供参考支持我的话:-12
单词边界可以出现在以下三个位置之一:
单词字符是字母数字;减号不是。取自Regex Tutorial。
单词边界是一个位置,前面是一个单词字符,后面没有一个单词,或者后跟一个单词字符,前面没有一个字符。
我谈到\b
风格的正则表达式边界实际上是here。
简短的故事是他们是有条件的。他们的行为取决于他们的下一步。
# same as using a \b before:
(?(?=\w) (?<!\w) | (?<!\W) )
# same as using a \b after:
(?(?<=\w) (?!\w) | (?!\W) )
有时这不是你想要的。请参阅我的其他答案进行详细说明。
查看有关边界条件的文档:
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有点打败我,所以他获得了投票。
在搜索像.NET
,C++
,C#
和C
这样的单词时,我遇到了一个更糟糕的问题。您可能会认为计算机程序员比将语言命名为难以编写正则表达式的语言更好。
无论如何,这是我发现的(主要来自http://www.regular-expressions.info,这是一个很棒的网站):在大多数版本的正则表达式中,与短手字符类\w
匹配的字符是按字处理为单词字符的字符边界。 Java是个例外。 Java支持\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();
}
然后在你的测试或主要功能:
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
的元字符。当我在重复地问自己“它是什么,它是什么”时,我确实无法理解它的含义。在使用the website进行一些尝试之后,我会在每个单词的开头和单词的结尾处注意粉红色的垂直破折号。那个时候我很清楚它的含义。它现在正是字(\w
) - 边界。
我的观点仅仅是以极其理解为导向。应该从另一个答案中检验它背后的逻辑。
我想解释一下Alan Moore的答案
单词边界是一个位置,前面是一个单词字符,后面没有一个单词,或者后跟一个单词字符,前面没有一个字符。
假设我有一个字符串“这是一只猫,她很棒”,只有当这个字母存在于“一个字的边界”,即字母a
里面时,我应该用字母“a”替换所有出现的字母。猫'不应该被替换。
所以我将执行正则表达式(在Python中)
re.sub("\ba","e", myString.strip())
//用a
取代e
所以输出将是这是e
猫e
nd她是e
wesome
我相信你的问题是因为-
不是一个单词字符。因此,单词边界将在-
之后匹配,因此不会捕获它。字符边界在字符串中的第一个字符和最后一个字符之前匹配,以及字符字符或非字符字符之前的任何位置,以及相反之后。另请注意,字边界是零宽度匹配。
一种可能的选择是
(?:(?:^|\s)-?)\d+\b
这将匹配任何以空格字符和可选短划线开头的数字,并以字边界结束。它还将匹配从字符串开头开始的数字。