正则表达式(preg_split):如何基于分隔符进行切割,但不包括双引号中的分隔符?

5

I split this:

1 2 3 4/5/6 "7/8 9" 10

将内容转换为:

1
2
3
4
5
6
"7/8 9"
10

使用preg_split()

我的问题是,如何根据分隔符拆分字符串,但要排除在引号对中的分隔符?

我想避免首先捕获引号中的内容,并希望它是一个一行代码。

3个回答

5

您可以使用:

$s = '1 2 3 4/5/6 "7/8 9" 10';
$arr = preg_split('~("[^"]*")|[ /]+~', $s, -1, PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY);

print_r( $arr );

输出:

Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => "7/8 9"
    [7] => 10
)

+1 用到了很少出现在答案中的有用 preg_split 标志。 :) - zx81
感谢 @zx81:在这种情况下使用这些标志使得正则表达式非常简单,也可以在非 PCRE 正则表达式引擎中使用。 - anubhava

5
您可以使用以下内容。
$text = '1 2 3 4/5/6 "7/8 9" 10';
$results = preg_split('~"[^"]*"(*SKIP)(*F)|[ /]+~', $text);
print_r($results);
解释
在交替运算符的左侧,我们匹配引号内的任何内容,使子模式失败,用(*SKIP)(*F)的回溯控制强制正则表达式引擎不再重试子字符串。交替运算符的右侧匹配空格字符或不在引号内的斜杠符号。 输出
Array
(
    [0] => 1
    [1] => 2
    [2] => 3
    [3] => 4
    [4] => 5
    [5] => 6
    [6] => "7/8 9"
    [7] => 10
 )

谢谢解释! - theamycode
哈哈。起初我把它解释为讽刺,然后我想起这篇文章是关于正则表达式的。嘿嘿嘿。 - theamycode

4

另一种方法是使用可选组:

$arr = preg_split('~(?:"[^"]*")?\K[/\s]+~', $s);

该模式"[^"]*"[/\s]+匹配一个带引号的部分,其后跟一个或多个空格和斜杠。但是由于您不想删除带引号的部分,所以在其后放置了\K\K从匹配结果中删除左侧已匹配的所有内容。使用此技巧,当发现带引号的部分时,正则表达式引擎仅返回其后的空格或斜杠,并在它们上进行拆分。
由于空格或斜杠前并不总是有带引号的部分,因此您只需要使用非捕获组(?:...)和问号?使其成为可选项。

这里很好地使用了\K +1。 - hwnd
请问您能否解释一下这个表达式的含义?感谢您的帮助! - theamycode
@theamydance:我添加了一个解释。 - Casimir et Hippolyte

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接