固定长度的正则表达式后顾断言检测到了可变长度的后顾断言问题。

5

这是我想要运行的代码:

$str = 'a,b,c,d';
return preg_split('/(?<![^\\\\][\\\\]),/', $str);

正则表达式如下所示:

/(?<![^\\][\\]),/

这是一个简单的固定长度的负回顾后发现,用于“前面不是反斜杠然后是任意字符”。

这个正则表达式在http://www.phpliveregex.com上运行得非常好。

但是当我尝试运行以上代码时,出现错误:

Warning:  preg_split() [function.preg-split]: Compilation failed: lookbehind assertion is not fixed length at offset 13

更糟糕的是,一位程序员在他的5.4.24 PHP服务器上测试了这段代码,它运行得很好。

这让我相信我的问题与我几乎无法控制的服务器配置有关。我被告知我的PHP版本为5.2.*

是否有任何绕过/替代preg_replace()的方法?


6
可能不是真正的5.2版本。它对我有效,你可以在这里看到它在哪些版本失败(在4.3.0-4.4.4和5.0.0-5.1.6中失败)。请注意你正在运行一个“古老”的PHP版本。 - Wrikken
@Wrikken 哦,我的天啊,从来不知道这个工具。太棒了。) - raina77ow
2
你可以使用'/(?<!(?<!\\\\)\\\\),/',它在所有版本中都能成功匹配(注意:修复了先前版本评论中的逻辑错误)。 - Wrikken
1
然而,这是否按预期拆分字符串 a\\\,b?(或:使用转义引号的 'a\\\\\\,b')。 - Wrikken
1
FWIW:我更倾向于匹配而不是分割,以获得与其中的\的数量无关的可靠行为:preg_match_all('/(?:[^\\\\,]|\\\\.)+/u',$str,$matches);(旧的“不是转义或定界符,或者是直接跟随任何你喜欢的转义 - 序列”) - Wrikken
显示剩余6条评论
3个回答

3
问题是由PCRE 6.7中修复的错误引起的。引用更改日志

否定的单字符类在回溯断言中,如(?<=[^f]),不能被识别为固定长度,导致一个不正确的编译错误"lookbehind assertion is not fixed length"

PCRE 6.7在2006年11月的PHP 5.2.0中引入。由于您仍然存在此错误,这意味着它仍然存在于您的服务器上 - 因此,对于基于preg-split的解决方法,您必须使用没有负字符类的模式。例如:
$patt = '/(?<!(?<!\\\\)\\\\),/';
// or...
$patt = '/(?<![\x00-\x5b\x5d-\xFF]\x5c),/';

然而,我觉得这种方法有点奇怪:如果,符号之前恰好有三个反斜杠呢?或者五个?或者任何奇数个?在这种情况下,逗号应该被视为“转义”,但显然你不能创建一个可变长度的回顾表达式来覆盖这些情况。

仔细想想,可以使用preg_match_all,并使用常见的交替技巧来覆盖转义符号:

$str = 'e ,a\\,b\\\\,c\\\\\\,d\\\\';
preg_match_all('/(?:[^\\\\,]|\\\\(?:.|$))+/', $str, $matches);
var_dump($matches[0]);

演示

我真的认为我在这里涵盖了所有问题,那些尾随斜杠真是致命的)


非常感谢!这是一个组织得很好、信息丰富的答案。正是SO需要的那种内容 :) - Georges Oates Larsen

1
避免否定字符类的方法(我写\x5c代替很多反斜杠以更清晰地表达)
$result = preg_split('/(?<!(?!\x5c).\x5c),/s', $str);

关于这种方法本身:

如果您试图在未转义逗号上进行拆分,则使用回顾后发是错误的方法,因为您无法检查逗号之前未定义的反斜杠数量。您有几种可能解决此问题:

$result = preg_split('/(?:[^\x5c]|\A)(?:\x5c.)*\K,/s', $str);

或者

$result = preg_split('/(?<!\x5c)(?:\x5c.)*\K,/s', $str);

或者适用于 PHP 版本大于 5.2.4。
$result = preg_split('/\x5c{2}(*SKIP)(?!)|(?<!\x5c),/s', $str);

0

我认为您正在使用较旧的PHP版本,因为您的错误出现在PHP 5.1.6或更低版本。

您可以在此处检查无法工作的演示

enter image description here

另一方面,它适用于PHP 5.2.16或更高版本:

工作演示

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接