【问题标题】:Regex to match multiple number groups between two characters正则表达式匹配两个字符之间的多个数字组
【发布时间】:2018-01-14 19:06:35
【问题描述】:

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

<@399969178745962506> hello to <@!104729417217032192>

我有一本包含两者的字典,如下所示:

{"399969178745962506", "One"},
{"104729417217032192", "Two"}

我的目标是将&lt;@399969178745962506&gt; 替换为该数字键的值,在本例中为One

Regex.Replace(arg.Content, "(?<=<)(.*?)(?=>)", m => userDic.ContainsKey(m.Value) ? userDic[m.Value] : m.Value);

我当前的正则表达式如下:(?&lt;=&lt;)(.*?)(?=&gt;) 仅匹配 &lt;&gt; 之间的所有内容,在这种情况下将同时保留 @399969178745962506@!104729417217032192

我不能只忽略@ 标志,因为! 标志并非每次都存在。所以最好只获取类似\d+的数字

我需要弄清楚如何仅获取 &lt;&gt; 之间的数字,但我一生都无法弄清楚如何。

非常感谢您的帮助!

【问题讨论】:

    标签: c# .net regex


    【解决方案1】:

    要从给定格式中提取数字,请使用此正则表达式模式:

    (?<=<@|<@!)(\d+)(?=>)
    

    查看它的实际效果:https://regexr.com/3j6ia

    【讨论】:

      【解决方案2】:

      在 C# 中,您可以使用 2 种方法:基于(因为后视模式可以是可变宽度)的环视和捕获组方法。

      基于环视的方法

      可以轻松帮助您在正确上下文中获取数字的模式是

      (?<=<@!?)\d+(?=>)
      

      regex demo

      (?&lt;=&lt;@!?) 是正向回溯,要求 &lt;=&lt;=! 紧邻当前位置的左侧,(?=&gt;) 是正向前瞻,要求 &gt; 字符紧邻当前位置的右侧.

      捕获方法

      您可以使用以下模式来捕获预期的&lt;...&gt; 子字符串中的数字:

      <@!?(\d+)>
      

      详情

      • &lt;@ - 文字 &lt;@ 子字符串
      • !? - 可选的感叹号
      • (\d+) - 捕获匹配一个或多个数字的组 1
      • &gt; - 文字 &gt; 符号。

      请注意,您需要的值可以通过match.Groups[1].Value 访问,如上面的 sn-p 所示。

      用法:

      var userDic = new Dictionary<string, string> {
              {"399969178745962506", "One"},
              {"104729417217032192", "Two"}
          };
      var p =  @"<@!?(\d+)>";
      var s = "<@399969178745962506> hello to <@!104729417217032192>";
      Console.WriteLine(
          Regex.Replace(s, p, m => userDic.ContainsKey(m.Groups[1].Value) ?
              userDic[m.Groups[1].Value] : m.Value
          )
      ); // => One hello to Two
      // Or, if you need to keep <@, <@! and >
      Console.WriteLine(
          Regex.Replace(s, @"(<@!?)(\d+)>", m => userDic.ContainsKey(m.Groups[2].Value) ?
              $"{m.Groups[1].Value}{userDic[m.Groups[2].Value]}>" : m.Value
          )
      ); // => <@One> hello to <@!Two>
      

      请参阅C# demo

      【讨论】:

        【解决方案3】:

        您可以使用非捕获组将所需模式的部分排除在组内:

        (?<=<)(?:@?!?)(.*?)(?=>)
        

        或者,您可以命名内部组并使用命名组来获取它:

        (?<=<)(?:@?!?)(?<yourgroupname>.*?)(?=>)
        

        通过m.Groups["yourgroupname"].Value 访问它 - 更多信息请参见 f.e. How do I access named capturing groups in a .NET Regex?

        【讨论】:

        • 有没有办法只获取该捕获中的数字?这样&lt;@399969178745962506&gt; hello to &lt;@!104729417217032192&gt; 就变成了[0] = 399969178745962506, [1] = 104729417217032192
        • @Ezzy 使 @!non-capturing 组中可选 .* 之前 - 查看更改
        【解决方案4】:

        正则表达式(?:&lt;@!?(\d+)&gt;)

        详情

        (?:)非捕获组

        &lt;@ 匹配字符

        ? 匹配 0 次和 1 次

        (\d+)第一个捕获组\d+匹配一个数字(等于[0-9])

        Regex demo

        string text = "<@399969178745962506> hello to <@!104729417217032192>";
        Dictionary<string, string> list = new Dictionary<string, string>() { { "399969178745962506", "One" }, { "104729417217032192", "Two" } };
        
        text = Regex.Replace(text, @"(?:<@!?(\d+)>)", m => list.ContainsKey(m.Groups[1].Value) ? list[m.Groups[1].Value] : m.Value);
        
        Console.WriteLine(text); \\ One hello to Two
        Console.ReadLine();
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-09-26
          • 1970-01-01
          • 2023-04-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多