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)
は正しく一致しており、16 進エディタでファイルを分析すると、ファイルが本来あるべきレイアウトになっていることが確認されます。
では、なぜ|\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'