不规则的RegEx行为

时间:2012-12-12 12:31:57

标签: php regex pcre

我有一个字符串:

$day = "11.08.2012 PROC BRE-AMS 08:00-12:00 ( MIETWAGEN MIT BAK RES 6049687886 ) Y AMS-AMS 13:15-19:15"

我有一个正则表达式:

$data = preg_split("/(?=[A-Z]{1,4}[\s]+[A-Z]{3}[\-][A-Z]{3}[\s]+)/", $day);

预期的$data - 数组应为:

array
      0 => string '11.08.2012 ' (length=11)
      1 => string 'PROC 08:00-12:00 ( MIETWAGEN MIT BAK RES 6049687886 ) ' (length=22)
      2 => string 'Y AMS-AMS 13:15-19:15' (length=21)

但我的结果是:

0 => string '11.08.2012 ' (length=11)
      1 => string 'P' (length=1)
      2 => string 'R' (length=1)
      3 => string 'O' (length=1)
      4 => string 'C BRE-AMS 08:00-12:00 ( MIETWAGEN MIT BAK RES 6049687886 ) ' (length=59)
      5 => string 'Y AMS-AMS 13:15-19:15' (length=21)

我无法追溯这里发生的事情。有人可以解释一下吗?

2 个答案:

答案 0 :(得分:3)

简而言之,问题是你的模式中的(?= ...)子表达式匹配一个位置。我明白这正是你的意图;问题是,下一个匹配是在(?=)中指定的模式结束匹配时开始的,而是在前瞻+ 1符号匹配的位置

让我们详细检查一下这个过程。第一次尝试拆分时,它会遍历字符串,直到它到达星号标记的位置:

11.08.2012 *PROC BRE-AMS 08:00-12:00

...它可以匹配给定的模式。对于下一次尝试,起始位置'沿着'一个符号碰撞,所以现在我们在这里:

11.08.2012 P*ROC BRE-AMS 08:00-12:00

...瞧,我们再次可以匹配这种模式,因为那个{1,4}量词!这就是您获得这些“不规则”PRO符号的方式。


这是为了解释,现在是“如何修复”部分。我想,最简单的方法就是在你的分割模式中加入这个小小的转折:

$data = preg_split('/\b(?=[A-Z]{1,4}\s+[A-Z]{3}-[A-Z]{3}\s+)/', $day);

我们仍然匹配位置 - 但现在这个位置应该是将“单词”符号与非单词符号分开的位置。同样的想法可以用负面的后观模式来表达:

$data = preg_split('/(?<![A-Z])(?=[A-Z]{1,4}\s+[A-Z]{3}-[A-Z]{3}\s+)/', $day);

......我想,这实际上更精确,但不那么优雅。 )

这里有两个旁注:1)当你需要指定一个符号时,不要使用字符类语法(简单 - - - 或'快捷'一个,如\s); 2)使用单引号来分隔您的模式,除非您想在其中插入一些变量。

答案 1 :(得分:2)

连字符是字符类中的元字符。如果你想在一个字符类中包含一个连字符,你必须反斜杠转义它(虽然在这种特殊情况下它可以工作,因为你的字符类只有一个连字符)。

如果需要包含拆分字符串,请将前瞻的开头锚定到单词边界,以便仅测试前1-4个字符序列的第一个字母:

/(?=\b[A-Z]{1,4}\s+[A-Z]{3}-[A-Z]{3}\s+)/'