匹配不同的单词顺序正则表达式

时间:2013-01-14 23:59:51

标签: regex perl bash sed

我一直在努力尝试在单个Regex系列中匹配一组相对简单的可能的单词顺序。

基本上,我想匹配这些(在其他语法相似的)可能性:

  

“设置var on”

     

“将var设置为关闭”

     

“set var on”

     

“set var off”

     

“设置var”

     

“设置在var”

     

“设置在var”

     

“set off var”

我需要的唯一群组是“ var ”(可以是任何一个单词)和,它们将始终打开或关闭。这是基本的想法。

考虑到这一点,有两种可能的语法结构:

(on/off) (perhaps a word) (a word)

(a word) (on/off)

我能够使用以下正则表达式独立匹配这些可能性:

/((on |off )([a-z]{1,})? ([a-z]{2,}))/i


/([a-z]{2,}) (on|off)/i

所以,我想我可以这样做:

/(((on |off )([a-z]{1,})? ([a-z]{2,})))|(([a-z]{2,}) (on|off))/i

这只是(短语1)|(短语2),但是短语2总是匹配“set off”,认为“set”是名称。我也尝试过:

/((?!set)) (((on |off )([a-z]{1,})? ([a-z]{2,})))|(([a-z]{2,}) (on|off))/i

没有成功。


编辑1:另外,我忽略了这些短语可以在文件的任何地方找到;他们不是独立的。

例如:“这是设置var 的方式”与“设置var ”的可能性相同


问题:

  1. 在没有必要的情况下,我可以一起完成这项工作的最佳方式是什么 分开匹配?

  2. 有没有办法强制匹配正则表达式OR语句的订单?

2 个答案:

答案 0 :(得分:2)

'the'可能总是出现在'var'之前:

((the)? var)

'set'总是从表达式开始:

^set

'on'和'off'是互斥的,但需要一个:

(on|off)

'var'和'on'/'off'一个接一个地出现,没有特别的顺序。现在一起:

^set ((the)? var (on|off)|(on|off) (the)? var)$

注意:我是.NET开发人员。正则表达式是非常标准的,上面应该可以工作,但可能有更有效的方法在perl中编写它。

答案 1 :(得分:0)

每当您尝试匹配复杂数据时,您应该尝试创建语法。 Perl正则表达式允许您通过(?(DEFINE)...)指定递归语法。

use strict; use warnings; use feature 'say';
my $grammar = qr(
    set \s+ (?:the \s+)? (?<variable>(?&VAR)) \s+ (?:to \s+)? (?<value>(?&VAL))
  | set \s+ (?<value>(?&VAL)) \s+ (?:the \s+)? (?<variable>(?&VAR))

  (?(DEFINE)
    (?<VAL> on | off) # edit only here to add new values
    (?<VAR> (?!the|(?&VAL)) \w+)
  )
)x; # /x -- whitespace is irrelevant

while(<>){
  if (/$grammar/) { say "> val: $+{value} var: $+{variable}" }
  else            { say "> no match" }
}

要注意的语法:(?&rule)调用命名规则。名为capture的(?<name>pattern)允许通过%+哈希进行访问。也用于在(DEFINE)块中声明规则。

示例会话:

set the switch to off!
> val: off var: switch
I would like to set something on fire...
> val: on var: something
set on the set!
> val: on var: set
set on the set off something
> val: on var: set
set on off
> no match

请注意,我通过断言变量与值不匹配来使语法明确无误。但是,上面的示例确实显示了一些可能未按预期解析的有趣案例。

有关在正则表达式中编写语法的更强大方法,请查看Regexp::Grammars