我需要拆分包含逗号的字符串。我已经找到像(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"
}
我想使用括号内的 not 逗号来分割字符串,因为这是我爆炸失败时唯一的情况。
答案 0 :(得分: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);
答案 1 :(得分: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)
正如所料。
答案 2 :(得分:0)
比创建数组然后过滤结果更优雅,您可以在这个单功能单行中使用preg_split()
:
代码:(Demo)
$string='A, B (one, two), C';
var_export(preg_split('/(?:\([^)]*\)(*SKIP)(*FAIL))|, /',$string));
输出:
array (
0 => 'A',
1 => 'B (one, two)',
2 => 'C',
)
(*SKIP)(*FAIL)
是一种在匹配前取消子字符串资格的技术。[^)]*
是.
(点)的更快替代品。 *如果你有嵌套的括号表达式,这个模式将不起作用...为该场景编写一个模式有点超出了这个问题的范围。