【问题标题】:Separate regex clauses单独的正则表达式子句
【发布时间】:2015-03-11 15:28:14
【问题描述】:

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

示例

允许的关键字:

  • 包含
  • 开始于
  • 等于
  • 结束于

可选字符:!

- 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)

【问题讨论】:

  • 您能否提供一个您可能正在解析的字符串的示例?
  • (?&lt;action&gt;!?(startswith|endswith|contains|equals))\((?&lt;field&gt;\w+),(?&lt;value&gt;\w+)\)
  • @1000000000 在灰色框中。 :)

标签: c# .net regex pattern-matching


【解决方案1】:

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

@"(?&lt;!\S)(?&lt;action&gt;!?(?:startswith|endswith|contains|equals))\((?&lt;field&gt;\w+),(?&lt;value&gt;\w+)\)"

格式化

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

【讨论】:

  • 像魅力一样工作,正是我想要的。
【解决方案2】:

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

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

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

DEMO

【讨论】:

  • 问题是,我需要捕获!也是。
【解决方案3】:

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

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

【讨论】:

  • 这可行,但是它会导致 4 个捕获组而不是 3 个。
【解决方案4】:

为什么不使用

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

您将匹配几乎所有可能的边界+“!?”在 ?&lt;action&gt; 组内仅使用一次,并且您的操作将包含带有或不带有 ! 符号的方法名称。

这是一些测试代码:

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;

【讨论】:

    猜你喜欢
    • 2012-07-02
    • 1970-01-01
    • 1970-01-01
    • 2015-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多