【问题标题】:Regular expression where part of string must be number between 0-100字符串的一部分必须是 0-100 之间的数字的正则表达式
【发布时间】:2009-12-15 18:50:46
【问题描述】:

我需要验证序列号。为此,我们在 C# 中使用正则表达式,并且某个产品,序列号的一部分是“自午夜以来的秒数”。一天有 86400 秒,但是如何验证它是这个字符串中的 5 位数字呢?:

654984051-86400-231324

我不能用这个概念:

[0-8][0-6][0-4][0-0][0-0]

因为那时86399 将无效。我该如何克服呢?我想要类似的东西:

[00000-86400]

更新
我想明确表示我知道 - 并同意 - “当有更简单的方法时不要使用正则表达式” 学派。 Jason's answer 正是我想要的,但是这个序列号验证适用于通过我们系统的所有序列号 - 目前没有针对这些特定序列号的自定义验证代码。 在这种情况下我有充分的理由寻找正则表达式解决方案。

当然,如果没有,那么这使得对这些特定产品进行自定义验证的理由不可否认,但我想在采用需要更改代码的解决方案之前充分探索这一途径。

【问题讨论】:

  • 有些人在遇到问题时会想“我知道,我会使用正则表达式”。现在他们有两个问题。 ——杰米·扎温斯基
  • 不是真的,但我似乎不记得我读过的博客文章。仍然是一个很好的报价......
  • @benjamin 我不是那些人中的一员,实际上我做出了一个合理且合理的决定来在这种情况下使用正则表达式。我真的不想使用它们,但如果有一个有效,那将是一个配置更改。如果没有,我需要编写自定义验证代码,那么这对我们的系统影响更大,并且会带来更多开销。
  • 如果正则表达式是您唯一的工具,在这种情况下,您可以考虑不使用c# 标记您的问题。
  • 刚刚理解了您所说的“代码更改”等的含义。我以前曾研究过一些人所说的“遗留”系统,所以我想我知道您的意思。它确实使它成为一个艰难的选择......我很想说制作这样一个正则表达式将是一个很好的妥协,但我不想成为“下一个人”,当有一个错误。添加这个验证逻辑真的是一个巨大的变化吗?只做正则表达式似乎是以后会后悔的事情。

标签: c# regex numbers


【解决方案1】:

不使用正则表达式?如果您正在努力想出正则表达式来解析它,这说明它可能太复杂了,您应该找到更简单的东西。当一个简单的时候,我认为在这里使用正则表达式绝对没有任何好处

int value;
if(!Int32.TryParse(s, out value)) {
    throw new ArgumentException();
}
if(value < 0 || value > 86400) {
    throw new ArgumentOutOfRangeException();
}

可以正常工作。它是如此清晰且易于维护。

【讨论】:

  • Regex 是一个很棒的、强大的工具,但我认为每当出现解析/验证问题时,人们就会过于频繁和过快地使用它。
  • 哇,别急——这个序列号验证适用于通过我们系统的所有序列号——这些特定的序列号没有自定义验证码。我知道尽可能避免使用正则表达式,但是在这种情况下是有充分理由的。
  • 这听起来像是在您的系统中添加挂钩的好理由。
【解决方案2】:

您不想为此尝试使用正则表达式,您最终会得到一些难以理解、笨拙且难以修改的东西(有人可能会建议一个 :)。您要做的是使用正则表达式匹配字符串以确保它包含所需的 格式 数字,然后提取匹配组并使用算术比较检查范围。例如,在伪代码中:

match regex /(\d+)-(\d+)-(\d+)/
serial = capture group 2
if serial >= 0 and serial <= 86400 then
    // serial is valid
end if

【讨论】:

    【解决方案3】:

    生成正则表达式以匹配任意数值范围 http://utilitymill.com/utility/Regex_For_Range

    产生以下正则表达式:

    \b0*([0-9]{1,4}|[1-7][0-9]{4}|8[0-5][0-9]{3}|86[0-3][0-9]{2}|86400)\b
    

    输出说明:

    First, break into equal length ranges:
      0 - 9
      10 - 99
      100 - 999
      1000 - 9999
      10000 - 86400
    
    Second, break into ranges that yield simple regexes:
      0 - 9
      10 - 99
      100 - 999
      1000 - 9999
      10000 - 79999
      80000 - 85999
      86000 - 86399
      86400 - 86400
    
    Turn each range into a regex:
      [0-9]
      [1-9][0-9]
      [1-9][0-9]{2}
      [1-9][0-9]{3}
      [1-7][0-9]{4}
      8[0-5][0-9]{3}
      86[0-3][0-9]{2}
      86400
    
    Collapse adjacent powers of 10:
      [0-9]{1,4}
      [1-7][0-9]{4}
      8[0-5][0-9]{3}
      86[0-3][0-9]{2}
      86400
    
    Combining the regexes above yields:
      0*([0-9]{1,4}|[1-7][0-9]{4}|8[0-5][0-9]{3}|86[0-3][0-9]{2}|86400)
    

    在这里测试: http://osteele.com/tools/rework/

    【讨论】:

      【解决方案4】:

      使用标准的“这不是特别是正则表达式问题”警告,

      [0-7]\d{4}|8[0-5]\d{3}|86[0-3]\d{2}|86400 
      

      【讨论】:

      • Robert Harvey 的版本还可以处理 10000 以下的非 0 填充数字。
      【解决方案5】:

      如果您真的需要一个纯正则表达式解决方案,我相信这会起作用,尽管其他发帖人提出了一个很好的观点,即仅验证它们是数字,然后使用匹配组来验证实际数字。

      ([0-7][0-9]{4}) | (8[0-5][0-9]{3}) | (86[0-3][0-9]{2}) | (86400)
      

      【讨论】:

      • 希望有第三次魅力。
      【解决方案6】:

      我会使用正则表达式结合一些 .NET 代码来实现这一点。纯正则表达式解决方案不会轻松或有效地处理大量数字范围。

      但这会:

      Regex myRegex = new Regex(@"\d{9}-(\d{5})-\d{6}");
      String value = myRegex.Replace(@"654984051-86400-231324", "$1");
      

      在这种情况下,这将获取值 86400。然后您只需按照 Jason 的回答检查捕获的数字是否在 0 到 86400 之间。

      【讨论】:

        【解决方案7】:

        我不相信这在正则表达式中是可能的,因为这不是可以作为正则语言的一部分进行检查的东西。换句话说,有限状态自动机无法识别该字符串,因此正则表达式也无法识别。

        编辑:这可以通过正则表达式识别,但不能以优雅的方式识别。它需要一个怪物 链(例如:00000|00001|000020{1,5}|0{1,4}1|0{1,4}2)。对我来说,必须列举如此多的可能性,这清楚地表明,虽然它在技术上是可行的,但它是不可行或不可管理的。

        【讨论】:

        • 这是真的吗?我对FSA不太了解,但假设的反例是“00000|00001|... .... |86400”
        • 当然可以,因为 0 到 86400 之间的每个整数的字符串表示形式都是有限集。所有有限集都可以被有限状态自动机接受。
        • 关于我的遗漏,你们俩都是对的。我已经编辑了我的答案
        • 通过以编程方式生成正则表达式以“优雅”的方式是可行的......但这会使问题陈述颠倒......无论如何,根据共识,RegEx 绝对不合适这种类型的用例。
        • 生成一个 518399 字符串并不完全是我所说的优雅,在我看来,解析和比较效率非常低。
        猜你喜欢
        • 2012-12-24
        • 1970-01-01
        • 1970-01-01
        • 2022-01-12
        • 2020-10-19
        • 1970-01-01
        • 2021-12-10
        • 2021-09-27
        相关资源
        最近更新 更多