(*跳过)(*失败) 魔法
This 现场 PHP 演示 https://ideone.com/woTUa8显示以下两个选项的输出(带或不带分号)。
这就是您所需要的:
$splits = preg_split('~\([^)]*\)(*SKIP)(*F)|;~', $sql);
See demo http://regex101.com/r/bT5vD0看看我们是在右边的分号上分开的。
Output:
[0] => BEGIN
[1] => INSERT INTO TABLE_A (a, b, c) VALUES('42', '12', '\'ab\'c; DEF')
[2] => INSERT INTO TABLE_B (d, e, f) VALUES('42', '43', 'XY\'s Z ;uvw')
[3] => COMMIT
[4] =>
空项目 #4 是决赛另一侧的比赛;
。另一种选择是保留分号(见下文)。
选项 2:保留分号
如果您想保留分号,请执行以下操作:
$splits = preg_split('~\([^)]*\)(*SKIP)(*F)|(?<=;)(?![ ]*$)~', $sql);
Output:
[0] => BEGIN;
[1] => INSERT INTO TABLE_A (a, b, c) VALUES('42', '12', '\'ab\'c; DEF');
[2] => INSERT INTO TABLE_B (d, e, f) VALUES('42', '43', 'XY\'s Z ;uvw');
[3] => COMMIT;
解释
这个问题是这个问题中解释的技术的一个经典案例“正则表达式-匹配模式,排除...” https://stackoverflow.com/q/23589174/
在交替的左侧|
,正则表达式\([^)]*\)
比赛完成(parentheses)
然后故意失败,之后引擎跳到字符串中的下一个位置。右侧与;
您想要的单词,我们知道它们是正确的,因为它们与左侧的表达式不匹配。现在可以安全地拆分它了。
在选项 2 中,我们保留分号,右侧的匹配匹配一个位置,但不匹配字符。该位置由后视断言(?<=;)
,它断言;
紧接在该位置之前,并且负向前看(?![ ]*$)
,它断言接下来的内容不是字符串末尾的可选空格(因此我们避免最后一个空匹配)。
示例代码
请检查现场 PHP 演示 https://ideone.com/woTUa8.
参考
- 如何匹配(或替换)除 s1、s2、s3... 情况之外的模式 https://stackoverflow.com/q/23589174/
- 关于匹配模式的文章,除非... http://www.rexegg.com/regex-best-trick.html
- 前向和后向零长度断言 http://www.regular-expressions.info/lookaround.html
- 掌握前瞻和后瞻 http://www.rexegg.com/regex-lookarounds.html
- 特殊回溯控制动词 http://perldoc.perl.org/perlre.html#Special-Backtracking-Control-Verbs