2

我有以下行,用于分隔 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 or \x3B(这没有用,因为\x3B在整个文件中多次单独出现)。管道空间之后的多个字符似乎出现了问题......有点。\x3B$并且\x00\x3B都会导致整个正则表达式失败。但是,无论如何,仅寻找 $ 都会失败。这似乎是 $ 锚的问题,而不是其他任何问题,尽管这显然不是这里唯一的问题。

导致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'
4

1 回答 1

0

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

(?=(a|b))
于 2012-06-29T04:43:03.190 回答