为什么这个正则表达式中的$匹配不匹配?

时间:2012-06-29 03:47:17

标签: php regex preg-match-all lookahead lookaround

我有以下行,用于分隔GIF文件中的帧:

preg_match_all('/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=\x00\x21\xF9\x04)/s', $fileContents, $matches, PREG_SET_ORDER);

如果您熟悉GIF文件格式,您可能会注意到一个主要缺陷 - 它不会检测到最后一帧,因为前瞻仅适用于帧头。

相反,如果我将正则表达式更改为:'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=\x00\x21\xF9\x04|\x3B$)/s,其中\x3B是文件终止符(后跟文件/字符串的实际结尾),整个操作失败,并且它甚至不能匹配一次。

我已经在Kodos中对此进行了测试,但由于这是二进制数据,我能做的最好的是纯文本等效,它完全按预期工作。函数preg_match('/\x00\x3B$/', $fileContents) 按原样进行匹配,并在十六进制编辑器中对文件进行分析,确认它的布局应该是应该的。

那么,为什么在前瞻中添加|\x3B$会使它完全失败?

注意:是的,有用于处理gif图像的库。这个问题纯粹是关于过程,而不是最终结果。

编辑:我注意到管道空间可能实际上不是问题;正则表达式很乐意匹配\x00\x21\xF9\x04 \x3B(这没用,因为\x3B在整个文件中多次出现)。管道空间之后的多个字符似乎发生了这个问题。 \x3B$\x00\x3B都会导致整个正则表达式失败。然而,无论如何,只是寻找$失败。对于$ anchor而言,这似乎是一个问题,而不是其他任何事情,尽管这显然不是唯一令人困惑的事情。

导致 0 匹配的排列:

//Grouping within lookahead:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=(\x00\x21\xF9\x04|\x3B$))/s'
//Moving lookahead within frame subpattern:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?(?=\x00\x21\xF9\x04|\x3B$))/s'
//Both of the above:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?(?=(\x00\x21\xF9\x04|\x3B$)))/s'
//Separating to two lookaheads:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)((?=\x00\x21\xF9\x04)|(?=\x3B$))/s'
//Just looking for the end anchor without \x3B:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=\x00\x21\xF9\x04|$)/s'
//Just trying to find the end of the file:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=$)/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)$/s'
//Trying to find \x00\x3B, the last two bytes:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=\x00\x21\xF9\x04|\x00\x3B)/s'
//With some more grouping experiments:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=(\x00\x21\xF9\x04|\x00\x3B))/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=(\x00\x21\xF9\x04)|(\x00\x3B))/s'
//Moving file end outside of lookahead:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)((?=\x00\x21\xF9\x04)|$)/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)((?=\x00\x21\xF9\x04)|\x3B$)/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)((?=\x00\x21\xF9\x04)|\x00\x3B)/s'
//Moving file end before header:
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=$|\x00\x21\xF9\x04)/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=\x3B$|\x00\x21\xF9\x04)/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=\x00\x3B|\x00\x21\xF9\x04)/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=($)|(\x00\x21\xF9\x04))/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=(\x3B$)|(\x00\x21\xF9\x04))/s'
'/(?P<frame>\x00\x21\xF9\x04.(?P<delay>..).\x00\x2C.*?)(?=(\x00\x3B)|(\x00\x21\xF9\x04))/s'

1 个答案:

答案 0 :(得分:0)

您可能需要将管道分隔值分组在一对自己的括号中:

(?=(a|b))