【问题标题】:Regex Counting By 3s正则表达式计数 3s
【发布时间】:2013-12-27 06:06:10
【问题描述】:

我正在自学正则表达式,并找到了一个测验网站,该网站一直在帮助我找到更多适用于它们的应用程序,并帮助我扩展我对它们工作原理的了解。

我发现一个问题要求我形成一个正则表达式来匹配 3 的倍数的 10 位数字。我能想到的唯一方法是让正则表达式识别数字的值并能够以数学方式操纵它们。这怎么可能?

换句话说,什么正则表达式匹配

0003
0006
0351
1749

但不匹配

0005
0011
0361
4372

【问题讨论】:

  • 是 regex.alf.nu 吗?这个谜题有一个正则表达式,它并不完全依赖于数字的多样性,我相信这将是最短的正则表达式。否则,您可以查看this site
  • 这实际上是针对 regex.alf.nu 的。我尝试使用 hobbs 的解释来解决问题,最终得到了比 wcp 更强大的东西,但仍然是错误的。阅读您的(杰瑞)链接帮助我注意到我忽略了复杂的 mod 0 案例。花了我一段时间,但我找到了。谢谢大家!
  • 整洁!如果您将通用正则表达式用于三的倍数,它应该可以工作。也许您忘记使用锚点^$ 来确保检查整个字符串?

标签: regex string-matching digit


【解决方案1】:

首先,您需要从一个数字可以被三整除的规则开始,当且仅当它的数字之和可以被三整除(证明这需要一点数论,但它有助于看到 9、99、 999 等都是 3 的倍数,因此 1、10、100、1000 等在除以 3 时对余数的贡献都相同。

然后,注意有三种数字:

  • 三的倍数:0、3、6 和 9。这些等价于 0 (mod 3)。
  • 大于三的倍数:1、4 和 7。这些等价于 1 (mod 3)。
  • 2 大于 3 的倍数:2、5 和 8。它们相当于 -1 (mod 3)。按照惯例,这个类被命名为 2,但 -1 对我们更有用。因为 1 + 2 = 0 (mod 3),-1 是 2 的合法名称。

那么,数字 0、3、6 和 9 是 3 的倍数。如果我们在任意位置添加类 0 中的任意数量的数字,则该数字仍然是三的倍数(因此 33、999 和 963 都是三的倍数)。如果我们在任何地方添加一个类 1 的数字,我们需要添加另一个类 -1 的数字,或者再添加两个类 1 的数字> 将余数带回 0。同样,如果我们在任何地方添加一个来自 -1 类的数字,我们要么需要添加另一个类 1 的数字,要么再添加两个-1 类的数字将余数带回 0。

这是 wcp 的答案,格式为 perl /x 正则表达式以提高可读性:

/
(   [0369] # 0
  | [147] [0369]* [258] # 1 + 0 + -1 = 0
  | (   [258] # -1
      | [147] [0369]* [147] # 1 + 0 + 1 = -1
    ) # -1
    (   [0369] # 0
      | [258] [0369]* [147] # -1 + 0 + 1 = 0
    )* # 0
    (   [147] # 1
      | [258] [0369]* [258] # -1 + 0 + -1 = 1
    ) # 1 ... -1 + 0 + 1 = 0
)+
/x

正则表达式匹配余数为 0 的数字组。第一个分支只匹配 0 类的数字;第二个分支匹配余数上升到 1 然后回到 0 的组;第三个分支匹配余数下降到 -1 然后回到 0 的组。它的构造方式有一些巧妙之处(我认为,一个较少使用的正则表达式将有五个主要分支而不是三个),但 cmets 应该足以让你跟随它。

【讨论】:

  • 非常感谢。我没有考虑通过 mod 余数形成字符串。我发现了几篇关于可以在正则表达式中使用的基本数学的文章,并专注于这个方向。
【解决方案2】:

就像@Jerry 在评论中说的那样,你可以使用这个:

([0369]|[147][0369]*[258]|([258]|[147][0369]*[147])([0369]|[258][0369]*[147])*([147]|[258][0369]*[258]))+

更短

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-29
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2021-08-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多