我正在尝试从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$/
这有效,它与1
,3
和5
相匹配。但它也匹配15
或13
。
让数字不能在它们之间结合的最佳方法是什么?
----编辑
使用群组,现在似乎正常运作。无论如何,有没有办法获得代表范围的正则表达式?例如,保留前面的示例:
lucky = Regexp.build(1..12)
"7" =~ lucky # => true
"13" =~ lucky # => false
"0" =~ lucky # => false
"5" =~ lucky # => true
Regexp.build生成的正则表达式必须匹配1到12之间的所有值,但不能再匹配。我一直在网上搜索,我发现以编程方式生成这种正则表达式很复杂。是否有任何具体或预定义的方法来完成此任务?
http://utilitymill.com有一个递归函数来完成它,但我认为它有点复杂。
答案 0 :(得分:2)
/(^|\D)1(\D|$)|(^|\D)3(\D|$)|(^|\D)5(\D|$)/
此正则表达式代码与1 3 5不同,它与13和15不匹配。
如果我误解了任何事情,那就详细解释一下你想要的东西。
谢谢
答案 1 :(得分:1)
答案 2 :(得分:0)
您想要匹配开头和结尾的单个项目。这可以通过括号分组来实现。例如:/^(1|3|5)$/
答案 3 :(得分:0)
问题是你的模式允许in-word(in-number?)匹配。我会用这个:
/\b(?:3|7)\b/
它只允许使用3
或7
的单个字母。
在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。所以,我的建议是使用正则表达式来处理简单的事情,并利用他们擅长的东西 - 提取与模式匹配的值,然后使用其他代码来验证它们是否在范围内或真正有效。