用两个分隔符对PHP preg_split进行分割,除非分隔符在引号内

4

继上次我关于preg_split的问题得到了快速回答,感谢nick;我真的想将场景扩展到当分隔符在引号内时不拆分字符串。例如:

如果我有字符串foo = bar AND bar=foo OR foobar="foo bar",我希望在每个空格或=字符处拆分字符串,但在返回的数组中包含=字符(目前已经很好地实现了),但如果这两个分隔符之一在引号内,则不要拆分字符串。

我已经做到了这一点:

<!doctype html>
<?php

$string = 'foo = bar AND bar=foo';

$array = preg_split('/ +|(=)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

?>
<pre>
<?php

print_r($array);

?>
</pre>

这让我想到:
Array
(
    [0] => foo
    [1] => =
    [2] => bar
    [3] => AND
    [4] => bar
    [5] => =
    [6] => foo
)

但是,如果我将字符串更改为:
$string = 'foo = bar AND bar=foo OR foobar = "foo bar"';

我希望数组变成这样:

Array
(
    [0] => foo
    [1] => =
    [2] => bar
    [3] => AND
    [4] => bar
    [5] => =
    [6] => foo
    [6] => OR
    [6] => foobar
    [6] => =
    [6] => "foo bar"
)

请注意,由于它被引号包含,因此"foo bar"没有按空格拆分。

真的不确定如何在正则表达式中实现此操作,或者是否有更好的方法,但是非常感谢您的所有帮助!

提前感谢大家!

3个回答

6

尝试

$array = preg_split('/(?: +|(=))(?=(?:[^"]*"[^"]*")*[^"]*$)/', $string, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);

The

(?=(?:[^"]*"[^"]*")*[^"]*$)

part是一个向前查看断言,确保字符串中未来的引号字符数为偶数,因此如果当前位置在引号之间,则匹配失败:

(?=      # Assert that the following can be matched:
 (?:     # A group containing...
  [^"]*" #  any number of non-quote characters followed by one quote
  [^"]*" #  the same (to ensure an even number of quotes)
 )*      # ...repeated zero or more times,
 [^"]*   # followed by any number of non-quotes
 $       # until the end of the string
)

不是楼主,但我试图理解这个。这个想法是,如果引号字符不是偶数,那么你当前正在引用的部分中间,不应该进行拆分,对吗? - KRyan
1
@DragoonWraith:没错。我假设我们的字符串中不会有任何转义引号。这些也可以加入到正则表达式中,但我不想让它变得比必要的更复杂。 - Tim Pietzcker
非常好,谢谢。非常棒;我本来想评论说正则表达式无法处理这个问题。我从未想过使用前瞻来确保我们不在引用部分中,以实现双引号数量为偶数。 - KRyan

2

我能够通过添加引号字符串作为分隔符来完成这个操作,类似于:

"(.*?)"| +|(=)

引用的部分将被捕获。看起来这有点牵强,我没有进行广泛的测试,但至少对你的示例有效。

好主意。这应该有效,除非引用字符串跨越多行。 - Tim Pietzcker
太棒了,我还添加了单引号检查 ['/"(.*?)"|(=)|\'(.*?)\'| +/'] - 这正好符合我所需的。然而,对于其他寻找类似答案的人来说,这种方法会去掉引号,而Tim的方法则保留它们。这种方式最适合我,但Tim的方式也很出色!谢谢你们两个! - Jonathon Oates
@JonathonDavidOates 如果你想保留引号,只需将括号放在引号外面(例如 (".*?"))。我以为你的示例数组没有包含它们,但我现在看到它确实包含了。 - Explosion Pills

0

但为什么要分割呢?

看了一下这个旧问题后,我想到了一个简单的解决方案,使用 preg_match_all 而不是 preg_split。我们可以使用这个简单的正则表达式来指定我们想要的内容:

"[^"]*"|\b\w+\b|=

请查看在线演示


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