作为更大的正则表达式的一部分,我想符合以下限制:
这意味着以下内容应该匹配:
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})
这不能满足我的需要。我的查询甚至可以使用正则表达式吗?
答案 0 :(得分:3)
您可以使用这种模式:
\A(?=\d{11}\z)(?:(\d)(?!\d*\1\d))*(\d)(?=\d*\2\d)(?:(\d)(?!\d*\3\d))+\d\z
模式细节:
这个想法是将字符串描述为由非重复数字包围的重复数字。
使用capture group,lookahead断言和backreference:(\d)(?=\d*\1)
您可以使用相同的模式来确保数字没有重复,但这次使用否定前瞻:(\d)(?!\d*\1)
要在搜索重复项时不考虑最后一位(数字编号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