preg_split有两种模式(其中一种引用)

时间:2012-11-08 15:26:00

标签: php regex preg-split

我想在PHP中拆分包含引用和不带引号的子串的字符串 假设我有以下字符串:

"this is a string" cat dog "cow"  

splitted数组应该如下所示:

array (  
[0] => "this is a string"  
[1] => "cat"  
[2] => "dog"  
[3] => "cow"  
)

我正在用正则表达式进行一些努力,我想知道是否只用一个正则表达式/ preg_split-Call就可以实现......

我尝试的第一件事是:

[[:blank:]]*(?=(?:[^"]*"[^"]*")*[^"]*$)[[:blank:]]*

但是这只能正确地拆分数组[0]和数组[3] - 其余部分按每个字符基础进行拆分。

然后我找到了这个链接:
PHP preg_split with two delimiters unless a delimiter is within quotes

(?=(?:[^"]*"[^"]*")*[^"]*$)

在我看来这是一个很好的起点。但是,我的示例中的结果与第一个正则表达式相同。

我尝试将两者结合起来 - 首先是引用字符串的一个,然后是第二个子正则表达式,它应该省略引用的字符串(因此[^“]):

(?=(?:[^"]*"[^"]*")*[^"]*$)|[[:blank:]]*([^"].*[^"])[[:blank:]]*

因此有2个问题:

  1. 只用一个正则表达式/ preg_split-Call甚至可以达到我想要的效果吗?
  2. 如果是,我会很感激如何正确组装正则表达式

1 个答案:

答案 0 :(得分:3)

由于匹配不能重叠,您可以像这样使用preg_match_all

preg_match_all('/"[^"]*"|\S+/', $input, $matches);

现在$matches[0]应该包含您要查找的内容。正则表达式将首先尝试匹配带引号的字符串,然后停止。如果没有这样做,它将只收集尽可能多的非空白字符。由于从左到右尝试了替换,因此引用的版本优先。

编辑:但这不会删除引号。为此,您可以使用捕获组:

preg_match_all('/(?|"([^"]*)"|(\S+))/', $input, $matches);

现在$matches[1]将包含您正在寻找的内容。 (?|就在那里,以便两个捕获组最终都在同一个索引处。

编辑2:由于您要求preg_split解决方案,这也是可能的。我们可以使用一个先行,断言空格后跟偶数引号(直到字符串结尾):

$result = preg_split('/\s+(?=(?:[^"]*"[^"]*")*$)/', $input);

当然,这不会删除引号,但可以在单独的步骤中轻松完成。