我有一个字符串:
$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)
我无法追溯这里发生的事情。有人可以解释一下吗?
答案 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}
量词!这就是您获得这些“不规则”P
,R
和O
符号的方式。
这是为了解释,现在是“如何修复”部分。我想,最简单的方法就是在你的分割模式中加入这个小小的转折:
$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+)/'