我目前正在编写一个库,用于匹配内容中的特定单词。
从本质上讲,它的工作方式是将单词编译为正则表达式,并通过所述正则表达式运行内容。
我想添加的一个功能是指定要匹配的给定单词必须以单词开头和/或结尾。例如,我有单词cat
。我指定它必须以单词开头,因此catering
将匹配,因为cat
在开头,但ducat
将不匹配cat
不以单词开头。
我想使用单词边界来完成这项工作,但在一些测试中,我发现它并没有像我预期的那样工作
采取以下措施,
preg_match("/(^|'b)@nimal/i", "something@nimal", $match);
preg_match("/(^|'b)@nimal/i", "something!@nimal", $match);
在上面的陈述中,我希望得到以下结果,
> false
> 1 (@nimal)
但结果恰恰相反,
> 1 (@nimal)
> false
在第一场比赛中,我预计它会失败,因为小组将吃掉@
,让nimal
对阵@nimal
,但显然没有。相反,该组匹配一个空字符串,因此@nimal
被匹配,这意味着@
被认为是单词的一部分。
在第二个例子中,我希望这群人吃!
,留下@nimal
来匹配其余的(它应该这样做)。相反,它似乎将!
和@
组合在一起形成一个单词,这通过以下匹配来确认
preg_match("/g'b!@'bn/i", "something!@nimal", $match);
你知道正则表达式为什么会这样做吗?
我只是喜欢一个清楚地记录单词边界是如何确定的页面,但我一生都找不到一个。
单词边界'b
在从'w
(单词字符)更改为'W
(非单词字符)时匹配。如果在@
之前有一个'b
,即'W
字符,则需要进行匹配。因此,为了匹配,您需要在@
之前添加一个单词字符
something@nimal
^^
===>由于g
和@
之间的字边界而匹配。
something!@nimal
^^
===>不匹配,因为!
和@
之间没有字边界,两个字符都是'W
我在进行类似匹配时遇到的一个问题是像can't
和it's
这样的单词,其中撇号被认为是单词/非单词边界(因为它是由'W
而不是'w
匹配的)。如果这对你来说可能是个问题,你应该排除撇号(以及有时出现的所有变体,如"answers"),例如创建一个类,例如['b^']
。
您可能还会遇到真正属于单词一部分的UTF8字符的问题(即我们人类对单词的意思),例如,根据如何编码单词(如Svašek
)来测试您的正则表达式。
因此,在解析正常的"语言"文本时,通常更容易找到"语言"边界,如空格字符(不仅是字面上的空格,还有包括换行符和制表符在内的完整类)、逗号、冒号、句号等(如果解析HTML,还可以使用尖括号)。YMMV。
@
不是单词字符的一部分(但是,在您的语言环境中,默认情况下它可能是"单词"字符是任何字母或数字或下划线字符,Source-,因此@
不是word
字符,因此不是'w
而是'W
,并且链接的任何'w'W
或'W'w
组合都标记'b
位置),因此始终是匹配的单词边界(在OP的正则表达式中)。
下面的正则表达式与您的正则表达式类似,只是使用了a
而不是@
。行首也是一个单词边界,所以不需要指定它:
$r = preg_match("/'b(animal)/i", "somethinganimal", $match);
var_dump($r, $match);
$r = preg_match("/'b(animal)/i", "something!animal", $match);
var_dump($r, $match);
输出:
int(0)
array(0) {
}
int(1)
array(2) {
[0]=>
string(6) "animal"
[1]=>
string(6) "animal"
}