2

我在 PHP 中使用 preg_split 函数来创建一个包含多个不同元素的数组。但是,我想排除一个恰好包含我 preg_splitting 的元素之一的字符串。

$array['stuff'] = preg_split('/\[#]|\ &amp  |\ &amp |\&amp |\&amp|\ &amp|\ &gt  |\ &gt |\&gt |\&gt|\ &gt|\ &  |\ & |\& |\&|\ &|\ \/  |\ \/ |\\/ |\\/|\ \/|\ >  |\ > |\> |\>|\ >|\ ,  |\ , |\, |\,|\, |\ ::  |\ :: |\:: |\ ::|\::|\ ::|\ :  |\ : |\: |\:|\ :|\ -  |\ - |\- |\-|\ -/', $array['stuff'] ) ;

我想做的是从匹配拆分中排除诸如“foo-bar”之类的字符串,因为它包含一个破折号。'foo-bar' 需要与我的目的完全匹配。

4

2 回答 2

3

如果您有很多异常,例如“foo-bar”,则生成的正则表达式将非常复杂。

您应该使用条件子模式,其中后向作为条件,前向作为其是模式:

$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 后面的破折号”来做到这一点,我们使用负前瞻:

\-(?!bar)

这成为我们的“是模式”。我们的“无模式”应该是\-或“任何破折号”。完整的正则表达式将是:

(?(?<=foo)\-(?!bar)|\-)

更新:要将其合并到您当前的正则表达式中,请在最后更改此部分:

|\ -  |\ - |\- |\-|\ -/

|\s?(?(?<=foo)\-(?!bar)|\-)\s?/
于 2011-08-06T15:59:15.760 回答
0

虽然我不能保证我的解决方案比没有人的双重环视模式更有效但我认为我的解决方案更容易阅读。(*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',
)

ps 如果您的输入字符串的开头或结尾可能有连字符,并且您不希望由 生成空元素,则在函数调用中preg_split()使用0and作为参数 3 和 4(分别)。PREG_SPLIT_NO_EMPTY

于 2018-08-02T07:24:34.810 回答