单独的正则表达式子句

Separate regex clauses

我需要将字符串与预定义关键字列表进行匹配,并将其捕获到一个组中,因为关键字前面可能有一个可选字符。

例子

允许的关键字:

可选字符:!

- input value              - comment
contains(field,value)      // OK
startswith(field,value)    // OK
test(field,value)          // NOK (test is not a valid keyword)
equals(field,value)        // OK
!startswith(field,value)   // OK  (optional character ! allowed)
!contains(field,value)     // OK  (optional character ! allowed)

正则表达式

我尝试使用以下正则表达式:

(?<action>!?startswith|endswith|contains|equals)\((?<field>\w+),(?<value>\w+)\)

我可以成功捕获组(actionfieldvalue),但正则表达式只允许 startswith 的可选字符。我怎样才能分开这两个规则并仍然捕获完整的关键字?像 capture=(optional ?)(any of the allowed keywords)

只需将 !? 放在捕获组之外。

@"!?\b(?<action>startswith|endswith|contains|equals)\((?<field>\w+),(?<value>\w+)\)"

\b !? 之后的单词边界是非常需要的。

DEMO

如果要捕获 !startswith 和 !contains,请使用以下命令...

(?<action>!?(startswith|endswith|contains|equals))\((?<field>\w+),(?<value>\w+)\)

为什么不用

(?<=^|\p{P}|\p{Zs}|\b)(?<action>\!?(?:startswith|endswith|contains|equals))\((?<field>\w+),(?<value>\w+)\)(?=$|\p{P}|\p{Zs}|\b) ?

你将匹配几乎所有可能的边界+“!?”仅在 ?<action> 组内使用一次,您的操作将保留带有或不带 ! 符号的方法名称。

下面是一些测试代码:

var MyRegex = new Regex(
      "(?<=^|\p{P}|\p{Zs}|\b)(?<action>\!?(?:startswith|endswit" +
      "h|contains|equals))\((?<field>\w+),(?<value>\w+)\)(?=$|\p" +
      "{P}|\p{Zs}|\b)",
    RegexOptions.IgnoreCase
    | RegexOptions.Multiline
    | RegexOptions.CultureInvariant
    | RegexOptions.Compiled
    );
// Capture all Matches in the InputText
var ms = MyRegex.Matches(@"contains(field,value)    OK
startswith(field,value)  OK
test(field,value)        NOK (test is not a valid keyword)
equals(field,value)      OK
!startswith(field,value) OK  (optional character ! allowed)
!contains(field,value)   OK  (optional character ! allowed)");

foreach (var capturedgroup in ms.Cast<Match>().ToList())
{
    var action = capturedgroup.Groups["action"].Value;
    var field = capturedgroup.Groups["field"].Value;
    var value = capturedgroup.Groups["value"].Value;
}

或者,如果您必须将方法名称检查为单独的字符串,请使用:

var MyRegex = new Regex("(?<action>\!?(?:startswith|endswith|contains|equals))\((?<field>\w+),(?<value>\w+)\)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
var ms = MyRegex.Match(@"!contains(field,value)");
var action = ms.Groups["action"].Value;
var field = ms.Groups["field"].Value;
var value = ms.Groups["value"].Value;

这是另一个。普遍的想法是将 !? 移到括号之外。

@"(?<!\S)(?<action>!?(?:startswith|endswith|contains|equals))\((?<field>\w+),(?<value>\w+)\)"

格式化

 (?<! \S )
 (?<action>                    #_(1 start)         
      !?
      (?:
           startswith
        |  endswith
        |  contains
        |  equals 
      )
 )                             #_(1 end)         
 \(
 (?<field> \w+ )               #_(2)         
 ,
 (?<value> \w+ )               #_(3)         
 \)