【问题标题】:RegEx to find numbers sequence in string separated by space with predefined maximum length正则表达式在字符串中查找由具有预定义最大长度的空格分隔的数字序列
【发布时间】:2017-08-02 09:01:08
【问题描述】:

抱歉标题令人困惑,我将尝试通过示例来解释这一点。目前我们有这个表达式来查找字符串中的数字序列
\b((\d[ ]{0,1}){13,19})\b
现在我想对其进行修改,使其符合这些规则
- 长度应在 13 到 19 个字符之间,不包括空格
- 每个号码簇必须至少有 3 位数字

表达式应将这些标记为匹配:

1234567890123
1234 5678 9012 345

不匹配:

123456789012 3
123 12 123 1 23134

我拥有的当前表达式会将它们全部标记为匹配。
Example

【问题讨论】:

  • 为什么你认为正则表达式是这里的最佳选择?
  • 为什么不直接删除空格,然后检查数字和长度?
  • 这是一个正则表达式甚至可以用于的东西吗?我能想到的纯正则表达式中唯一的解决方案是列出所有可能的数字簇组合。你匹配什么样的源字符串?匹配所有数字/空白簇(具有最大长度)会更好(并且可能更快),然后在不使用正则表达式的情况下检查它们。
  • @Nino 如果要删除空格,那么我将无法区分哪个集群有效(包含 3 个或更多字符)。除了给定的字符串将不仅包含数字,还包含字母
  • @IllidanS4 源字符串来自 word 文档,因此大小很大,将包含各种字符。早期的实现是使用正则表达式,因此如果可能的话,我想尝试通过更新现有表达式来实现这一点

标签: c# .net regex


【解决方案1】:

这可以通过环视来实现。

正则表达式可以改成如下:

\b(?<!\d )(?=(?:\d ?){13,19}(?! ?\d))(?:\d{3,} ?)+\b(?! ?\d)

这可以通过向前看来确保号码的长度在 13 到 19 位之间。然后它匹配 3 个或更多数字的组。然后它在找到所有 3 组后使用负前瞻来确保没有任何数字。如果有,我们发现了一个小于 3 的组。这适用于您提供的示例。

  • \b 确保它是“单词”的开头。
  • (?&lt;!\d ) 确保后面没有数字。
  • (?=(?:\d ?){13,19}(?! ?\d)) 向前看以确保号码长度在 13 到 19 位之间
    • (?:\d ?){13,19} 来自原创。 ?: 添加以使非捕获
    • (?! ?\d) 否定前瞻:如果得到19位后还有数字,则太大因此丢弃当前匹配
  • (?:\d{3,} ?)+ 匹配任意数量的大于 3 的簇(最少 13 个,最多 19 个由先行处理)
  • \b(?! ?\d) 查找集群的结尾。如果集群结束后还有数字,那么一定是集群太小了。

Test here

【讨论】:

  • SchoolBoy,我赞成你的回答,但你也可以用这个正则表达式实现同样的目标,对吧? / ^(?=(\d ?){13,19})(?:\d{3,} ?)+\b$/
  • @JBone 是的,尽管这要求数字始终位于一行并且数字是该行中唯一的内容。在这种情况下,我假设您可以在同一行上有多个东西,包括数字,因此需要额外的检查。我会从末尾删除 \b ,因为您已经使用 $ 锚点检查字符串结尾。
  • 哈哈,我现在明白你的意思了。谢谢。也是的,我忘了在最后删除 \b 。很好的收获。
  • 非常感谢
  • @EkaT 没问题!
【解决方案2】:

我还建议基于外观的以下解决方案:

\b\d(?!\d?\b)(?: ?\d(?!(?<= \d)\d?\b)){12,18}\b

regex demo

主要的一点是,我们只匹配不属于 1 位或 2 位组的下一个数字。

模式说明

  • \b - 起始字边界
  • \d(?!\d?\b) - 一个数字后面不跟 1 或 0 数字,然后是尾随的字边界(即如果是 121 之类的组,则失败)
  • (?: ?\d(?!(?&lt;= \d)\d?\b)){12,18} - 出现 12 到 18 次:
    • ? - 1 或 0 个空格
    • \d(?!(?&lt;= \d)\d?\b) - 任何单个数字后面不带 1 或 0 位数字边界(感谢 (?!\d?\b)),如果该 1 或 0 位数字前面有空格 + 1 位数字((?&lt;= \d) 后视确实那个)
  • \b - 词尾边界。

注意,如果您想在非数字上下文中匹配这些字符串(这意味着,如果您不希望在左侧和右侧允许任何数字),您还可以考虑在前面和(?! *\d) 在模式的末尾。

请注意,要匹配任何空格,您可以在模式中将文字空格替换为 \s

【讨论】:

    【解决方案3】:

    如果你可以使用 Linq,这将更容易维护:

    var myList = new List<string>
                        {
                        "1234567890123",
                        "1234 5678 9012 345",
                        "123456789012 3",
                        "123 12 123 1 23134"
                        };
    
    foreach(var input in myList)
    {
        var splitted = Regex.Split(input, @"\s+"); // Split on whitespace
    
        var length = splitted.Sum(x => x.Length); // Compute the total length
        var smallestGroupSize = splitted.Min(x => x.Length); // Compute the length of the smallest chunck
        Console.WriteLine($"Total lenght: {length}, smallest group size: {smallestGroupSize}");
    
        if (length < 13 || length > 19 || smallestGroupSize < 3)
        {
            Console.WriteLine($"Input '{input}' is incorrect{Environment.NewLine}");
            continue;
        }
    
        Console.WriteLine($"Input '{input}' is correct!{Environment.NewLine}");
    }
    

    产生:

    总长度:13,最小团体人数:13 输入“1234567890123”是正确的!

    总长度:15,最小团体人数:3 输入“1234 5678 9012 345”是正确的!

    总长度:13,最小组数:1 输入“123456789012 3”不正确

    总长度:14,最小组数:1 输入“123 12 123 1 23134”不正确

    【讨论】:

      猜你喜欢
      • 2015-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-21
      • 2023-04-08
      • 2014-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多