このスニペットは、ネストされた括弧で役立ちます。基本的なアイデアは、括弧がなくなるまで (*) を何らかの識別子に再帰的に置き換えることです。次に、文字列をコンマで分解してから、すべてを元に戻します。これは理想的な解決策ではありません - たった今約 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)
予想通り。