正则表达式单词边界在PHP中的工作原理是什么?

时间:2011-06-30 08:01:51

标签: php regex

我目前正在编写一个用于匹配内容中特定单词的库。

基本上它的工作方式是将单词编译成正则表达式,并通过所述正则表达式运行内容。

我要添加的功能是指定要匹配的给定单词是否必须开始和/或结束单词。例如,我有cat这个词。我指定必须开始一个单词,因此catering匹配,因为cat位于开头,但是ducat 不匹配,因为cat没有开始这个词。

我想使用word boundaries执行此操作,但在某些测试中,我发现它无法正常工作。

采取以下措施,

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);

为什么正则表达式会这样做?

我只是一个页面,清楚地记录了如何确定单词边界,我找不到我的生活。

3 个答案:

答案 0 :(得分:18)

单词边界\b匹配从\w(单词字符)到\W非单词字符的变化。如果您的\b字符@之前有\W,您希望匹配。因此,为了匹配,您需要在@

之前使用单词字符
something@nimal
        ^^

==>由于g@之间的单词边界而匹配。

something!@nimal
         ^^ 

==>不匹配,因为在!@之间没有字边界,两个字符都是\W

答案 1 :(得分:2)

我遇到类似匹配时遇到的一个问题是像can'tit's这样的词,其中撇号被视为单词/非单词边界(因为它与{{1}相匹配而不是\W)。如果这对您来说可能是一个问题,您应该排除撇号(以及有时出现的所有变体,如'和'),例如通过创建一个类,例如\w

你可能也会遇到UTF8字符的问题,这些字符确实是单词的一部分(即我们人类用单词表示的意思),例如测试你的正则表达式如何对[\b^']这样的单词进行编码。

因此,在解析普通语言时,通常会更容易。要查找的文字"语言"边界,例如空格字符(不仅仅是字面上的空格,而是完整的类,包括换行符和制表符),逗号,冒号,句号等(如果要解析HTML,则使用斜括号)。 YMMV。

答案 2 :(得分:0)

@不是单词字符的一部分(在您的语言环境中可能是这样,但默认 “单词”字符是任何字母或数字或下划线字符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"
}

输出:

{{1}}