想要匹配以like结尾的单词#
你好你好# 世界#
我尝试使用边界
\b\w+#\b
它不匹配。我认为\b
是一个非单词边界,但从这种情况下似乎不是这样
出奇
\b\w+#\B
火柴!
那么为什么在\B
这里有效而不是\b
!为什么\b
在这种情况下不起作用!
注意:
是的,我们可以使用\b\w+#(?=\s|$)
,但我想知道为什么\B
在这种情况下有效!
想要匹配以like结尾的单词#
你好你好# 世界#
我尝试使用边界
\b\w+#\b
它不匹配。我认为\b
是一个非单词边界,但从这种情况下似乎不是这样
出奇
\b\w+#\B
火柴!
那么为什么在\B
这里有效而不是\b
!为什么\b
在这种情况下不起作用!
注意:
是的,我们可以使用\b\w+#(?=\s|$)
,但我想知道为什么\B
在这种情况下有效!
\b
在单词中定义单词边界是不精确的。让我用look-ahead、look-behind和short-hand word character class来定义单词边界\w
。
单词边界\b
等价于:
(?:(?<!\w)(?=\w)|(?<=\w)(?!\w))
意思是:
就在前面,(至少)有一个字符是单词字符,而在后面,我们找不到单词字符(该字符不是单词字符,或者它是字符串的开头)。
或者
(注意这与 XOR 扩展为合取和析取有多么相似)
非单词边界\B
等价于:
(?:(?<!\w)(?!\w)|(?<=\w)(?=\w))
意思是:
在前面和后面,我们找不到任何单词字符。请注意,在此定义下,空字符串被视为非单词边界。
或者
(注意这与将 XNOR 扩展为合取和析取有多么相似)。
\w
由于\b
and的定义\B
取决于\w
1的定义,因此您需要查阅特定文档以确切了解\w
匹配的内容。
1大多数正则表达式风格\b
基于\w
. 好吧,除了 Java [Point 9]之外,在默认模式下,\w
它只支持 ASCII,并且\b
部分支持 Unicode。
在JavaScript中,它将[A-Za-z0-9_]
处于默认模式。
在.NET中,\w
默认情况下会 match ,如果指定了ECMAScript 选项[\p{Ll}\p{Lu}\p{Lt}\p{Lo}\P{Lm}\p{Nd}\p{Pc}]
,它将具有与 JavaScript 相同的行为。在Pc 类别的字符列表中,您只需知道不包括空格(ASCII 32)。
有了上面的定义,回答这个问题就变得容易了:
"hi hello# world#"
中hello#
,后面#
是空格(U+0020,Zs类),不是单词字符,#
本身也不是单词字符(Unicode中是Po类)。因此,\B
可以在这里匹配。(?<!\w)(?!\w)
在这种情况下使用分支。
在world#
,之后#
是字符串的结尾。由于#
不是单词字符,而且我们在前面找不到任何单词字符(那里什么都没有),\B
所以可以匹配 . 之后的空字符串#
。(?<!\w)(?!\w)
在这种情况下也使用分支。
Alan Moore 在评论中给出了很好的总结:
我认为要记住的关键点是正则表达式无法读取。也就是说,它们不处理文字,只处理字符。当我们说
\b
匹配一个单词的开头或结尾时,我们并不是说它会识别一个单词,然后像人类那样寻找它的端点。它只能看到当前位置之前的字符和当前位置之后的字符。因此,\b
仅表示当前位置可能是单词边界。由你来确定两边的角色应该是什么。
磅#
符号不被视为“单词边界”。
\b\w+#\b
不起作用,因为w+#
不被视为一个单词,因此它不会匹配world#
.
\b\w+6\b
另一方面是,因此它会匹配world6
。
“字字符”定义为:[A-Za-z0-9_]
.
简单地说:
\b
允许您使用\bword\b
. “单词字符”是可用于构成单词的字符。所有不是“单词字符”的字符都是“非单词字符”。
— http://www.regular-expressions.info/wordboundaries.html
和#
空格都是非单词字符,所以它们之间的隐形边界不是单词边界。因此\b
将不匹配它\B
并将匹配它。