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


string to array, split by single and double quotes

我正试图使用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))/";

但显然这是行不通的。

您可以将preg_splitPREG_SPLIT_DELIM_CAPTURE选项一起使用。正则表达式不如@Jan Turoń的反向引用方法优雅,因为所需的捕获组会混淆结果。

$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);

您可以仅使用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

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

  • /^([^''"]*)=>将初始位放置到第一个捕获组中的第一个引号(单引号或双引号)
  • (([''"]).*'3)=>在'' 2中捕获从初始引号(单引号或双引号)(在'' 3中捕获)到结束引号(必须与开头引号类型相同,因此为'' 3)的对应文本。regexp本质上是贪婪的,这一事实有助于从第一个引号到最后一个引号,无论里面有多少引号
  • (.*)$/=>捕获直到'' 4中结束

另一个使用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

注意:我最好创建一个类来完成这一壮举,这样就可以避免全局变量。

您可以在preg_match_all 中使用反向引用和非自由修饰符

$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

如果引号位于字符串的开头/末尾,只需去掉最终的空头/尾元素。