我在PHP中使用preg_split函数来创建一个包含几个不同元素的数组。但是,我想要排除碰巧包含我要预先分割的元素之一的字符串。
$array['stuff'] = preg_split('/'[#]|' & |' & |'& |'&|' &|' > |' > |'> |'>|' >|' & |' & |'& |'&|' &|' '/ |' '/ |''/ |''/|' '/|' > |' > |'> |'>|' >|' , |' , |', |',|', |' :: |' :: |':: |' ::|'::|' ::|' : |' : |': |':|' :|' - |' - |'- |'-|' -/', $array['stuff'] ) ;
我想做的是排除一个字符串,如'foo-bar'被分割匹配,因为它包含一个破折号。'foo-bar'需要完全匹配。
生成的正则表达式将非常复杂,特别是当你有很多像'foo-bar'这样的异常时。
您应该使用一个条件子模式,将向后看作为条件,并将向前看作为yes模式:
$res = preg_split('/(?(?<=foo)'-(?!bar)|'-)/', 'aasdf-fafsdf-foo-bar-asdf' );
var_dump( $res );
结果:array(4) {
[0]=>
string(5) "aasdf"
[1]=>
string(6) "fafsdf"
[2]=>
string(7) "foo-bar"
[3]=>
string(4) "asdf"
}
让我解释一下这里发生了什么。'-
意味着
匹配任意破折号
但是我们想要的是
匹配不属于foo-bar的任何破折号。
因为我们不能在正则表达式中实现它,所以我们稍微改变一下:
如果前面有foo而后面没有bar,则匹配中的任何破折号。
要实现if部分,我们使用条件子模式,语法如下:
(?(condition)yes-pattern|no-pattern)
我们的"条件"应该是"前面有foo"来检查,我们使用了后视:
(?<=foo)
如果这是真的,我们应该寻找"后面没有横杠的破折号"来做到这一点,我们使用负向前看:
'-(?!bar)
这就变成了我们的"yes-pattern"。我们的"无模式"应该是'-
或"任何破折号"。完整的正则表达式应该是:
(?(?<=foo)'-(?!bar)|'-)
UPDATE:要将其合并到当前的正则表达式中,请更改末尾的这一部分:
|' - |' - |'- |'-|' -/
|'s?(?(?<=foo)'-(?!bar)|'-)'s?/
虽然我不能保证我的解决方案在这种情况下比nobody的double look - around模式更有效,但我认为我的解决方案更容易阅读。(*SKIP)(*FAIL)
有效地匹配并丢弃您希望忽略的子字符串。在某些情况下,这种方法可能非常有用/有效/可维护。
代码(演示):
$string = 'I-like-candy-and-foo-bar-sandwiches';
var_export(preg_split('~foo-bar(*SKIP)(*FAIL)|-~', $string));
输出:array (
0 => 'I',
1 => 'like',
2 => 'candy',
3 => 'and',
4 => 'foo-bar',
5 => 'sandwiches',
)
老实说,我认为没有人的答案是有点过度设计的。它可以更简单地写成否定的向后看和否定的向前看……没有理由使用条件语法。
代码(演示):
$string = 'I-like-candy-and-foo-bar-sandwiches';
var_export(preg_split('~(?<!foo)-(?!bar)~', $string));
输出:array (
0 => 'I',
1 => 'like',
2 => 'candy',
3 => 'and',
4 => 'foo-bar',
5 => 'sandwiches',
)
注。如果您可能在输入字符串的开始或结束处有连字符,并且您不希望由preg_split()
生成空元素,那么在函数调用中使用0
和PREG_SPLIT_NO_EMPTY
作为参数3和4(分别)。