1

我有一个字符串:

$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 应该是:

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)

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

4

2 回答 2

3

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

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

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

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

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

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


这是为了解释,现在是“如何修复”部分。我想,最简单的方法是在拆分模式中添加这个小扭曲:

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

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

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

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

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

于 2012-12-12T12:40:29.080 回答
2

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

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

/(?=\b[A-Z]{1,4}\s+[A-Z]{3}-[A-Z]{3}\s+)/'
于 2012-12-12T12:35:26.383 回答