2

我需要拆分一个包含逗号的字符串。我已经为 ( str_getcsv) 之类的字符串找到了一些东西:

'A', 'B with a comma, eh', 'C'

但我的字符串是这样的,例如,值没有封闭字符:

A, B (one, two), C

我需要爆炸并获得:

array(3) {
  [0]=>
  string(1) "A"
  [1]=>
  string(12) "B (one, two)"
  [2]=>
  string(1) "C"
}

我想使用不在括号内的逗号来拆分字符串,因为这是在我的情况下发生的唯一一种情况 explode failed

4

3 回答 3

5

但是有一个解决方案可以满足您的疯狂愿望;)

$a = "(Z) X, (Y, W) A, B (one, two), C, D (E,F,G) H, I J";
$reg = '/[^(,]*(?:\([^)]+\))?[^),]*/';
preg_match_all($reg, $a, $matches);
$result = array_filter($matches[0]);
var_dump($result);
于 2012-06-16T09:40:13.213 回答
1

这个片段可以帮助我使用嵌套括号。基本上想法是用一些标识符递归替换 (*) 直到没有更多的括号。然后用逗号分解字符串,然后将所有内容放回原处。这不是理想的解决方案 - 刚刚在大约 30 分钟内完成,但它可以工作:) 它绝对可以以某种方式进行优化。

/**
 * Explode string by delimiter, but don't explode if delimiter is inside parenthesis.
 * This also support nested parenthesis - that's where pure RegExp solutions fails.
 * 
 * For example,
 *  $input = "one, two three, four (five, (six, seven), (eight)) (nine, ten), eleven";
 *  $output = array(
 *      'one',
 *      'two three',
 *      'four (five, (six, seven), (eight)) (nine, ten)',
 *      'eleven'
 *  );
 * 
 * @param string $input
 * @param string $delimiter = ,
 * @param string $open_tag = \(
 * @param string $close_tag = \)
 * @return array
 */
function exploder($input, $delimiter = ',', $open_tag = '\(', $close_tag = '\)')
{
    // this will match any text inside parenthesis
    // including parenthesis itself and without nested parenthesis
    $regexp = '/'.$open_tag.'[^'.$open_tag.$close_tag.']*'.$close_tag.'/';

    // put in placeholders like {{\d}}. They can be nested.
    $r = array();
    while (preg_match_all($regexp, $input, $matches)) {
        if ($matches[0]) {
            foreach ($matches[0] as $match) {
                $r[] = $match;
                $input = str_replace($match, '{{'.count($r).'}}', $input);
            }
        } else {
            break;
        }
    }
    $output = array_map('trim', explode($delimiter, $input));

    // put everything back
    foreach ($output as &$a) {
        while (preg_match('/{{(\d+)}}/', $a, $matches)) {
            $a = str_replace($matches[0], $r[$matches[1] - 1], $a);
        }
    }

    return $output;
}

$a = "one, two three, four (five, (six, seven), (eight)) (nine, ten), eleven";
var_dump(exploder($a));

这将输出:

array (size=4)
  0 => string 'one' (length=3)
  1 => string 'two three' (length=9)
  2 => string 'four (five, (six, seven), (eight)) (nine, ten)' (length=46)
  3 => &string 'eleven' (length=6)

正如预期的那样。

于 2013-03-25T00:17:26.720 回答
0

比创建一个数组然后过滤结果更优雅,您可以preg_split()在这个单函数单行器中使用:

代码:(演示

$string='A, B (one, two), C';
var_export(preg_split('/(?:\([^)]*\)(*SKIP)(*FAIL))|, /',$string));

输出:

array (
  0 => 'A',
  1 => 'B (one, two)',
  2 => 'C',
)

模式演示

  • (*SKIP)(*FAIL)是一种在匹配之前取消子字符串资格的技术。
  • 否定字符类[^)]*.(dot) 的更快替代方案。*如果您有嵌套的括号表达式,则此模式将不起作用......为该场景编写模式有点超出了这个问题的范围。
于 2017-10-15T02:51:25.870 回答