PHP和RegEx:用不在括号内的逗号(以及嵌套括号)拆分字符串

时间:2009-07-05 20:27:41

标签: php regex parsing split

两天前,我开始研究代码解析器而且卡住了。

如何用不在括号内的逗号分隔字符串,让我告诉你我的意思:

我要解析这个字符串:

one, two, three, (four, (five, six), (ten)), seven

我想得到这个结果:

array(
 "one"; 
 "two"; 
 "three"; 
 "(four, (five, six), (ten))"; 
 "seven"
)

但我得到了:

array(
  "one"; 
  "two"; 
  "three"; 
  "(four"; 
  "(five"; 
  "six)"; 
  "(ten))";
  "seven"
)

我如何在PHP RegEx中执行此操作。

提前谢谢!

7 个答案:

答案 0 :(得分:11)

您可以更轻松地做到这一点:

preg_match_all('/[^(,\s]+|\([^)]+\)/', $str, $matches)

但是如果使用真正的解析器会更好。也许是这样的:

$str = 'one, two, three, (four, (five, six), (ten)), seven';
$buffer = '';
$stack = array();
$depth = 0;
$len = strlen($str);
for ($i=0; $i<$len; $i++) {
    $char = $str[$i];
    switch ($char) {
    case '(':
        $depth++;
        break;
    case ',':
        if (!$depth) {
            if ($buffer !== '') {
                $stack[] = $buffer;
                $buffer = '';
            }
            continue 2;
        }
        break;
    case ' ':
        if (!$depth) {
            continue 2;
        }
        break;
    case ')':
        if ($depth) {
            $depth--;
        } else {
            $stack[] = $buffer.$char;
            $buffer = '';
            continue 2;
        }
        break;
    }
    $buffer .= $char;
}
if ($buffer !== '') {
    $stack[] = $buffer;
}
var_dump($stack);

答案 1 :(得分:7)

嗯...确定已标记为已回答,但由于您要求一个简单的解决方案,我会尽力尝试:

<?php
  $test = "one, two, three, , , ,(four, five, six), seven, (eight, nine)";
  $split = "/([(].*?[)])|(\w)+/";
  preg_match_all($split, $test, $out);
  print_r($out[0]);              
  die();
?>

输出

Array
(
    [0] => one
    [1] => two
    [2] => three
    [3] => (four, five, six)
    [4] => seven
    [5] => (eight, nine)
)

答案 2 :(得分:5)

你不能,直接。你至少需要可变宽度的lookbehind,最后我知道PHP的PCRE只有固定宽度的lookbehind。

我的第一个建议是首先从字符串中提取带括号的表达式。但是,我对你的实际问题一无所知,所以我不知道这是否可行。

答案 3 :(得分:2)

我想不出使用单个正则表达式来做到这一点的方法,但是很容易将一些有效的东西混在一起:

function process($data)
{
        $entries = array();
        $filteredData = $data;
        if (preg_match_all("/\(([^)]*)\)/", $data, $matches)) {
                $entries = $matches[0];
                $filteredData = preg_replace("/\(([^)]*)\)/", "-placeholder-", $data);
        }

        $arr = array_map("trim", explode(",", $filteredData));

        if (!$entries) {
                return $arr;
        }

        $j = 0;
        foreach ($arr as $i => $entry) {
                if ($entry != "-placeholder-") {
                        continue;
                }

                $arr[$i] = $entries[$j];
                $j++;
        }

        return $arr;
}

如果你这样调用它:

$data = "one, two, three, (four, five, six), seven, (eight, nine)";
print_r(process($data));

输出:

Array
(
    [0] => one
    [1] => two
    [2] => three
    [3] => (four, five, six)
    [4] => seven
    [5] => (eight, nine)
)

答案 4 :(得分:2)

笨拙,但它确实起作用......

<?php

function split_by_commas($string) {
  preg_match_all("/\(.+?\)/", $string, $result); 
  $problem_children = $result[0];
  $i = 0;
  $temp = array();
  foreach ($problem_children as $submatch) { 
    $marker = '__'.$i++.'__';
    $temp[$marker] = $submatch;
    $string   = str_replace($submatch, $marker, $string);  
  }
  $result = explode(",", $string);
  foreach ($result as $key => $item) {
    $item = trim($item);
    $result[$key] = isset($temp[$item])?$temp[$item]:$item;
  }
  return $result;
}


$test = "one, two, three, (four, five, six), seven, (eight, nine), ten";

print_r(split_by_commas($test));

?>

答案 5 :(得分:1)

我担心解析嵌套括号可能非常困难      one, two, (three, (four, five)) 只有RegExp。

答案 6 :(得分:1)

我觉得值得注意的是,你应该总是避免使用正则表达式。为此,您应该知道对于PHP 5.3+,您可以使用str_getcsv()。但是,如果您正在处理文件(或文件流),例如CSV文件,那么函数fgetcsv()可能就是您所需要的,并且自PHP4起就可以使用。

最后,我很惊讶没有人使用preg_split(),或者根据需要不能使用它?