我试图创建一个用于拆分字符串的正则表达式,但遗憾的是我的要求比简单拆分要复杂一些,所以我不能在PHP中使用preg_split()
所以我正在做的是在子表达式中匹配我的分隔符(或者更确切地说,它们的一部分),在另一个子表达式中匹配它前面的所有内容,并将字符串的结尾视为分隔符这个目的。考虑到这一点,我想出了以下内容:
([^?;]*)(?|\?([0-9]*)|(;)|$)
正如您所希望看到的那样,第一个子模式会查找一块没有任何分号问号的文本。在此之后,我有一个子模式匹配任何问号后跟一个可选数字(存储),或者是分号(存储)或字符串结尾。
问题在于我似乎在字符串结尾处得到一个无关紧要的空匹配,如下所示:
$sql = 'CALL foo(?0, ?1, ?2, ?3)';
preg_match_all('/([^?;]*)(?|\?([0-9]*)|(;)|$)/', $sql, $matches);
print_r($matches);
生成如下所示的输出:
Array
(
[0] => Array
(
[0] => CALL insert_host(?0
[1] => , ?1
[2] => , ?2
[3] => , ?3
[4] => )
[5] =>
)
[1] => Array
(
[0] => CALL insert_host(
[1] => ,
[2] => ,
[3] => ,
[4] => )
[5] =>
)
[2] => Array
(
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] =>
[5] =>
)
)
请注意$matches[0][5]
下的空白匹配;我希望在匹配括号后满足字符串大小写的结束,导致没有进一步的匹配,但它继续产生另一个匹配,我无法弄清楚原因。
所以我的问题是;为什么这里会产生额外的匹配,我该如何防止呢?
注意:我已经考虑过要求字符串大小写的结尾至少有一个字符,但这并不好,因为事实上我想要一个空的结果通配符位于字符串的位置,因为我试图模拟拆分函数的行为。例如,如果输入为SELECT ?
,我希望匹配SELECT ?
加上一个空字符串。这里的想法是,一旦我处理了任何匹配的分号,我就可以简单地用implode('?', $matches[1])
来重现带有数字通配符的语句。
答案 0 :(得分:0)
我相信我可能已经找到了解决问题的具体案例的替代方案;我所做的是翻转表达式,使得分隔符首先匹配,或者失败,字符串的开头,如下:
(?|\?([0-9]*)|(;)|^)([^?;]*)
这会在所有情况下产生预期结果:
preg_match_all('/(?|\?([0-9]*)|(;)|^)([^?;]*)/', 'CALL foo(?3, ?2, ?1, ?0)', $matches);
print_r($matches);
产地:
Array
(
[0] => Array
(
[0] => CALL foo(
[1] => ?3,
[2] => ?2,
[3] => ?1,
[4] => ?0)
)
[1] => Array
(
[0] =>
[1] => 3
[2] => 2
[3] => 1
[4] => 0
)
[2] => Array
(
[0] => CALL foo(
[1] => ,
[2] => ,
[3] => ,
[4] => )
)
)
虽然:
preg_match_all('/(?|\?([0-9]*)|(;)|^)([^?;]*)/', 'SELECT ?', $matches);
print_r($matches);
产地:
Array
(
[0] => Array
(
[0] => SELECT
[1] => ?
)
[1] => Array
(
[0] =>
[1] =>
)
[2] => Array
(
[0] => SELECT
[1] =>
)
)
但是,这只能起作用,因为我知道输入永远不会包含分隔符作为第一个字符;如果我提供一个它会遇到很多相同的问题,所以我不确定是否将其称为真正的解决方案。
我仍然有兴趣知道为什么我的原始表达式会得到一个额外的匹配,因为我希望贪婪的匹配意味着它是不可能的,因为一旦字符串的结尾匹配,应该没有什么可以找到的