4

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

"this is a string" cat dog "cow"  

拆分后的数组应如下所示:

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

我在使用正则表达式时有点挣扎,我想知道是否甚至可以通过一个正则表达式/preg_split-Call 来实现...

我尝试的第一件事是:

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

但这仅正确拆分了 array[0] 和 array[3] - 其余部分根据每个字符进行拆分。

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

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

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

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

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

因此有2个问题:

  1. 甚至可以通过一个 regex/preg_split-Call 来实现我想要的吗?
  2. 如果是,我将不胜感激有关如何正确组装正则表达式的提示
4

1 回答 1

4

由于匹配不能重叠,您可以这样使用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);

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

于 2012-11-08T15:29:33.580 回答