【问题标题】:Define a regex, which matches one digit twice and all others once定义一个正则表达式,它匹配一个数字两次,所有其他数字一次
【发布时间】:2014-08-23 13:00:33
【问题描述】:

作为更大的正则表达式的一部分,我想满足以下限制:

  1. 字符串有 11 位数字
  2. 所有数字都是数字
  3. 在前 10 位数字内,一个数字 [0-9](并且只有一个!)必须列出两次

这意味着以下应该匹配:

12345678914
12235879600

而这些不应该:

12345678903 -> none of the numbers at digits 1 to 10 appears twice
14427823482 -> one number appears more than twice
72349121762 -> two numbers appear twice

我尝试使用前瞻,但我所管理的只是正则表达式计算某个数字,即:

(?!.*0\1{2})

这不能满足我的需要。我的查询甚至可以使用正则表达式吗?

【问题讨论】:

  • 我认为正则表达式是不可能的。通过正则表达式,您可以定义一个结构。如果你知道你能得到的数字是多少。例如,您说我想要两位数 5。但在这里您希望根据后面的数字创建数字,所以这是不可能的。

标签: ruby-on-rails regex


【解决方案1】:

你可以使用这种模式:

\A(?=\d{11}\z)(?:(\d)(?!\d*\1\d))*(\d)(?=\d*\2\d)(?:(\d)(?!\d*\3\d))+\d\z

online demo

图案细节:

这个想法是将字符串描述为由非重复数字包围的重复数字。

使用capture grouplookahead 断言和backreference 可以轻松找到重复数字:
(\d)(?=\d*\1)

您可以使用相同的模式来确保数字没有重复,但这次使用负前瞻:(\d)(?!\d*\1)

要在搜索重复项时不考虑最后一个数字(digit n°11),您只需在反向引用后添加一个数字。 (\d)(?=\d*\1\d) (这样可以确保反向引用和字符串末尾之间至少有一位数字。)

请注意,在当前上下文中,所谓的重复数字是指没有立即或稍后跟在相同数字后面的数字。 (即在1234567891 中,第一个1 是重复数字,但最后一个1 不再是重复数字,因为它后面没有另一个1

\A                       # begining of the string
(?=\d{11}\z)             # check the string length (if not needed, remove it)
(?:(\d)(?!\d*\1\d))*     # zero or more non duplicate digits
(\d)(?=\d*\2\d)          # one duplicate digit
(?:(\d)(?!\d*\3\d))+     # one or more non duplicate digits
\d                       # the ignored last digit
\z                       # end of the string

另一种方式

这一次,您使用前瞻检查模式开头的重复项。一个前瞻确保有一个重复数字,一个负前瞻确保没有两个重复数字:

\A(?=\d*(\d)(?=\d*\1\d))(?!\d*(\d)(?=\d*\2\d)\d*(\d)(?=\d*\3\d))\d{11}\z

图案细节:

\A
(?=                       # check if there is one duplicate digit
    \d*(\d)(?=\d*\1\d)
)
(?!                       # check if there are not two duplicate digits
    \d*(\d)(?=\d*\2\d)    # the first
    \d*(\d)(?=\d*\3\d)    # the second
)
\d{11}
\z

注意:不过似乎第一种方式效率更高。

代码方式

您可以使用数组方法轻松检查您的字符串是否符合要求:

> mydigs = "12345678913"
=> "12345678913"
> puts (mydigs.split(//).take 10).uniq.size == 9
true
=> nil

【讨论】:

  • 很好的解释——对我来说似乎很合乎逻辑!但是我如何确保这仅适用于字符串的一部分(即 11 位数字中的前 10 位)。换句话说 - 我可以告诉前瞻在字符串结束之前停止重复检查一位数字吗?还是我必须改用lookbehinds?我在匹配示例方面犯了一个错误。最后缺少另一个随机数字,这将导致数字(应该匹配),例如:12345678911 或 65432198770
  • @Amin:如果我理解得很好,您想在有 11 位数字时忽略最后一位数字,但在只有 10 位数字时不忽略?还是字符串中总是有 11 位数字?
  • 后者 - 我的错误。限制是正确的,示例不是。所以字符串中总是有 11 位数字,但最后一位数字应该被忽略。它的唯一约束是 \d 而没有应用整个前瞻。我希望这会让它更清楚
  • 这很完美,我理解其中的大部分内容。但我将不得不更多地研究反向引用。正则表达式业务中的新手...谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-25
  • 2020-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多