固定长度的正则表达式背后抱怨可变长度的lookbehind

时间:2014-09-10 20:27:58

标签: php regex

以下是我尝试运行的代码:

$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()的变通方法/替代方法?

3 个答案:

答案 0 :(得分:3)

问题是由PCRE 6.7中修复的错误引起的。引用the changelog

  

一个被否定的单字符类没有被识别为   固定长度的后续断言,例如(?<=[^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),/';

但是,我发现整个方法有点奇怪:如果,符号前面有三个反斜杠,该怎么办?还是五个?或者他们中的任何奇数?在这种情况下,逗号应该被视为“转义”,但显然你不能创建一个可变长度的lookbehind表达式来覆盖这些情况。

在第二个想法中,可以使用preg_match_all代替,使用常见的替换技巧来覆盖转义的符号:

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

Demo

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

答案 1 :(得分:1)

避免被否定的字符类的方法(我写\x5c而不是很多反斜杠更清楚)

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

关于方法本身:

如果你试图拆分没有转义的逗号,那么你的错误方式就是一个lookbehind,因为你不能在逗号之前检查和定义反斜杠的数量。您有几种方法可以解决这个问题:

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

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

或用于PHP&gt; 5.2.4

$result = preg_split('/\x5c{2}(*SKIP)(?!)|(?<!\x5c),/s', $str);

答案 2 :(得分:0)

我认为你使用的是较旧的php版本,因为我的错误在 PHP 5.1.6 或更低时出现。

您可以查看 non working demo here

enter image description here

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

<强> Working demo

enter image description here