想要匹配以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由于\band的定义\B取决于\w1的定义,因此您需要查阅特定文档以确切了解\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并将匹配它。