字符串到数组,由单引号和双引号分隔

时间:2012-09-10 14:13:03

标签: php preg-split

我正在尝试使用php将字符串拆分为数组组件,使用"'作为分隔符。我只想分开最外面的字符串。这里有四个例子,每个例子都有所需的结果:

$pattern = "?????";
$str = "the cat 'sat on' the mat";
$res = preg_split($pattern, $str);
print_r($res);
/*output:
Array
(
    [0] => the cat 
    [1] => 'sat on'
    [2] =>  the mat
)*/

$str = "the cat \"sat on\" the mat";
$res = preg_split($pattern, $str);
print_r($res);
/*output:
Array
(
    [0] => the cat 
    [1] => "sat on"
    [2] =>  the mat
)*/

$str = "the \"cat 'sat' on\" the mat";
$res = preg_split($pattern, $str);
print_r($res);
/*output:
Array
(
    [0] => the
    [1] => "cat 'sat' on"
    [2] =>  the mat
)*/

$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen";
$res = preg_split($pattern, $str);
print_r($res);
/*output:
Array
(
    [0] => the
    [1] => 'cat "sat" on'
    [2] =>  the mat
    [3] => 'when "it" was'
    [4] =>  seventeen
)*/

你可以看到我只想按最外面的引号拆分,我想忽略引号中的任何引用。

我为$pattern提出的最接近的是

$pattern = "/((?P<quot>['\"])[^(?P=quot)]*?(?P=quot))/";

但显然这不起作用。

4 个答案:

答案 0 :(得分:2)

您可以将preg_splitPREG_SPLIT_DELIM_CAPTURE选项一起使用。正则表达式不像@JanTuroň的后向引用方法那么优雅,因为所需的捕获组会弄乱结果。

$str = "the 'cat \"sat\" on' the mat the \"cat 'sat' on\" the mat";
$match = preg_split("/('[^']*'|\"[^\"]*\")/U", $str, null, PREG_SPLIT_DELIM_CAPTURE);
print_r($match);

答案 1 :(得分:1)

您可以只使用preg_match

$str = "the \"cat 'sat' on\" the mat";
$pattern = '/^([^\'"]*)(([\'"]).*\3)(.*)$/';

if (preg_match($pattern, $str, $matches)) {
  printf("[initial] => %s\n[quoted] => %s\n[end] => %s\n",
     $matches[1],
     $matches[2],
     $matches[4]
  );
}

打印:

[initial] => the 
[quoted] => "cat 'sat' on"
[end] =>  the mat

以下是正则表达式的解释:

  • /^([^\'"]*) =&gt;将初始位放到第一个捕获组中的第一个引号(单个或双重)
  • (([\'"]).*\3) =&gt;在\ 2中捕获与初始引用(单个或双重)(在\ 3中捕获)相对应的文本,直到结束引号(必须与开头引号相同,因此为\ 3)。正则表达式本质上是贪婪的这一事实有助于从第一个引用到最后一个引用,无论内部有多少引号。
  • (.*)$/ =&gt;捕获到\ 4
  • 结束

答案 2 :(得分:1)

使用preg_replace_callback

的另一种解决方案
$result1 = array();
function parser($p) {
  global $result1;
  $result1[] = $p[0];
  return "|"; // temporary delimiter
}

$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen";
$str = preg_replace_callback("/(['\"]).*\\1/U", "parser", $str);
$result2 = explode("|",$str); // using temporary delimiter

现在您可以使用array_map

压缩这些数组
$result = array();
function zipper($a,$b) {
  global $result;
  if($a) $result[] = $a;
  if($b) $result[] = $b;
}
array_map("zipper",$result2,$result1);
print_r($result);

结果是

[0] => the 
[1] => 'cat "sat" on'
[2] =>  the mat 
[3] => 'when "it" was'
[4] =>  seventeen

注意:我可能会更好地创建一个完成此专长的类,因此可以避免全局变量。

答案 3 :(得分:0)

您可以在preg_match_all

中使用back referencesungreedy modifier
$str = "the 'cat \"sat\" on' the mat 'when \"it\" was' seventeen";
preg_match_all("/(['\"])(.*)\\1/U", $str, $match);
print_r($match[0]);

现在你有最外面的引用部分

[0] => 'cat "sat" on'
[1] => 'when "it" was'

您可以使用substrstrpos找到字符串的其余部分(黑盒解决方案)

$a = $b = 0; $result = array();
foreach($match[0] as $part) {
  $b = strpos($str,$part);
  $result[] = substr($str,$a,$b-$a);
  $result[] = $part;
  $a = $b+strlen($part);
}
$result[] = substr($str,$a);
print_r($result);

结果如下

[0] => the 
[1] => 'cat "sat" on'
[2] =>  the mat 
[3] => 'when "it" was'
[4] =>  seventeen

如果引号位于字符串的开头/结尾,则只删除最终的空标题/尾随元素。