【问题标题】:C# RegEx - get only first match in stringC# RegEx - 仅获取字符串中的第一个匹配项
【发布时间】:2014-07-22 21:06:31
【问题描述】:

我有一个如下所示的输入字符串:

level=<device[195].level>&name=<device[195].name>

我想创建一个正则表达式来解析每个 <device> 标签,例如,我希望从我的输入字符串中匹配两个项目:<device[195].level><device[195].name>

到目前为止,我对这个模式和代码有一些运气,但它总是将两个设备标签作为一个匹配项找到:

var pattern = "<device\\[[0-9]*\\]\\.\\S*>";
Regex rgx = new Regex(pattern);
var matches = rgx.Matches(httpData);

结果是matches 将包含一个值为&lt;device[195].level&gt;&amp;name=&lt;device[195].name&gt; 的结果

我猜一定有一种方法可以“终止”该模式,但我不确定它是什么。

【问题讨论】:

  • 没有时间给出完整的答案,但关键是非贪婪匹配。在 * 之后放置 ? 以使其匹配最小可能(非贪婪)而不是最可能(贪婪)。

标签: c# regex


【解决方案1】:

使用non-greedy quantifiers:

<device\[\d+\]\.\S+?>

此外,使用逐字字符串来转义正则表达式,这使它们更具可读性:

var pattern = @"<device\[\d+\]\.\S+?>";

作为旁注,我想在你的情况下使用 \w 而不是 \S 会更符合你的意图,但我离开了 \S 因为我不知道。

【讨论】:

  • 现在我希望投反对票的人证明我错了...regex101.com/r/kX3hK2/1
  • @Lucas ? after \d* 不是必需的,因为\d* 永远不会匹配]。此外,您的正则表达式将匹配 &lt;device[].&gt; - 这是常见的方式。
  • @dognose 你是对的?,我想我已经习惯了默认使用非贪婪。最终的结果是完全一样的。我离开了*,因为那是 OP 中的内容,我不知道提问者的用例。不过,这是否使它成为一个糟糕的答案?
  • @dognose:你知道用户输入字符串的内幕吗?说&lt;device[].&gt; 是常见的方式对我来说似乎很奇怪,因为它不是我经常看到的字符串,当然也不是 OP 说他拥有的字符串......
【解决方案2】:

取决于你需要匹配多少角度块的结构,但你可以做到

"\\<device.+?\\>"

【讨论】:

    【解决方案3】:

    我想创建一个正则表达式来解析每个&lt;device&gt; 标签

    I'd expect two items to be matched from my input string: 
       1. <device[195].level>
       2. <device[195].name>
    

    这应该可以。从索引 1 获取匹配组

    (<device[^>]*>)
    

    Live demo

    在程序中使用的字符串字面量:

    @"(<device[^>]*>)"
    

    【讨论】:

    • 请发表评论。
    • @dognose 我没明白。看看演示
    • @dognose 不会做出任何 OP 不应该的此类输入。
    • 您的“完美匹配,伙计”示例也很荒谬,因为它与 OP 所说的字符串完全不同。
    • 在这种情况下,我可以用数千种方法使其无效。
    【解决方案4】:

    更改您的重复运算符并使用\w 而不是\S

    var pattern = @"<device\[[0-9]+\]\.\w+>";
    

    String s = @"level=<device[195].level>&name=<device[195].name>";
    foreach (Match m in Regex.Matches(s, @"<device\[[0-9]+\]\.\w+>"))
             Console.WriteLine(m.Value);
    

    输出

    <device[195].level>
    <device[195].name>
    

    【讨论】:

      【解决方案5】:

      使用命名匹配组并创建 linq 实体投影。将有两个匹配项,从而将各个项目分开:

      string data = "level=<device[195].level>&name=<device[195].name>";
      
      string pattern = @"
      (?<variable>[^=]+)     # get the variable name
      (?:=<device\[)         # static '=<device'
      (?<index>[^\]]+)       # device number index
      (?:]\.)                # static ].
      (?<sub>[^>]+)          # Get the sub command
      (?:>&?)                # Match but don't capture the > and possible &  
      ";
      
       // Ignore pattern whitespace is to document the pattern, does not affect processing.
      var items = Regex.Matches(data, pattern, RegexOptions.IgnorePatternWhitespace)
                      .OfType<Match>()
                      .Select (mt => new
                        {
                           Variable = mt.Groups["variable"].Value,
                           Index    = mt.Groups["index"].Value,
                           Sub      = mt.Groups["sub"].Value
                        })
                       .ToList();
      
      items.ForEach(itm => Console.WriteLine ("{0}:{1}:{2}", itm.Variable, itm.Index, itm.Sub));
      
      /* Output
      level:195:level
      name:195:name
      */
      

      【讨论】:

        猜你喜欢
        • 2020-11-09
        • 2014-11-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-06-29
        相关资源
        最近更新 更多