如何创建regexp来检测整数和范围?

时间:2013-09-26 17:24:55

标签: ruby regex

我正在尝试从Ruby测验书中解决问题#6。这个问题说我必须为Regex类创建一个名为build()的新方法,其中传递整数或范围,它必须生成一个正则表达式来检测允许的数字。

例如:

lucky = Regexp.build(3, 7)
"7" =~ lucky # => true
"13" =~ lucky # => false
"3" =~ lucky # => true

month = Regexp.build(1..12)
"0" =~ month # => false
"1" =~ month # => true
"12" =~ month # => true

我开发了一个有缺陷的版本,但它没有按预期工作。我的问题是生成正确的正则表达式。我在Rubular中尝试的所有模式都没有采取应有的模式。例如,对于Regexp.build(1, 3, 5),我得到了一个看起来像这样的模式:

/^1|3|5$/

这有效,它与135相匹配。但它也匹配1513

让数字不能在它们之间结合的最佳方法是什么?

----编辑

使用群组,现在似乎正常运作。无论如何,有没有办法获得代表范围的正则表达式?例如,保留前面的示例:

lucky = Regexp.build(1..12)
"7" =~ lucky # => true
"13" =~ lucky # => false
"0" =~ lucky # => false
"5" =~ lucky # => true

Regexp.build生成的正则表达式必须匹配1到12之间的所有值,但不能再匹配。我一直在网上搜索,我发现以编程方式生成这种正则表达式很复杂。是否有任何具体或预定义的方法来完成此任务?

http://utilitymill.com有一个递归函数来完成它,但我认为它有点复杂。

4 个答案:

答案 0 :(得分:2)

/(^|\D)1(\D|$)|(^|\D)3(\D|$)|(^|\D)5(\D|$)/

此正则表达式代码与1 3 5不同,它与13和15不匹配。

如果我误解了任何事情,那就详细解释一下你想要的东西。

谢谢

答案 1 :(得分:1)

一个小提示:

/^1|3|5$/

装置

/^1//3//5$/

查看groups。它们将帮助您确保更改的范围不包括您的开始/结束锚点。

答案 2 :(得分:0)

您想要匹配开头和结尾的单个项目。这可以通过括号分组来实现。例如:/^(1|3|5)$/

答案 3 :(得分:0)

问题是你的模式允许in-word(in-number?)匹配。我会用这个:

/\b(?:3|7)\b/

它只允许使用37的单个字母。

http://rubular.com/r/0rRUfXdlTJ

进行测试

此模式适用于独立值或嵌入字符串中的数字。

\b是字边界标记,意味着必须从非字转换为字。一个词是[a-zA-Z0-9_]

使用您的测试:

"7" =~ /\b(?:3|7)\b/   # => 0
"13" =~ /\b(?:3|7)\b/  # => nil
"3" =~ /\b(?:3|7)\b/   # => 0

"0" =~ /\b(?:1|2|3|4|5|6|7|8|9|10|11|12)\b/   # => nil
"1" =~ /\b(?:1|2|3|4|5|6|7|8|9|10|11|12)\b/   # => 0
"12" =~ /\b(?:1|2|3|4|5|6|7|8|9|10|11|12)\b/  # => 0

其中=> 0表示在第一个字符索引处匹配的模式,而nil是未命中的。

也就是说,我不会尝试使用模式来强制执行范围,因为这样做会使它们成为他们并不真正有用的东西。看看用于测试可接受的IPv4数字的模式,或更糟的IPv6数字。要获得真正的乐趣,请查看the pattern for a valid email address。他们都有规范定义什么是有效价值的规格,但定义这些的模式是复杂的,超出了凡人的肯定。相反,使用模式来定位看起来像数字的东西,提取该值并测试它是否在可接受的范围内。

例如,这是来自Ruby的Resolv :: IPv4 :: Regex的IPv4模式:

/\A((?x-mi:0
               |1(?:[0-9][0-9]?)?
               |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
               |[3-9][0-9]?))\.((?x-mi:0
               |1(?:[0-9][0-9]?)?
               |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
               |[3-9][0-9]?))\.((?x-mi:0
               |1(?:[0-9][0-9]?)?
               |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
               |[3-9][0-9]?))\.((?x-mi:0
               |1(?:[0-9][0-9]?)?
               |2(?:[0-4][0-9]?|5[0-5]?|[6-9])?
               |[3-9][0-9]?))\z/

像IPv6这样的更长的价值使它变得更加困难。有关详细信息,请参阅Regular expression that matches valid IPv6 addresses。所以,我的建议是使用正则表达式来处理简单的事情,并利用他们擅长的东西 - 提取与模式匹配的值,然后使用其他代码来验证它们是否在范围内或真正有效。