0

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

例如:

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,35。但它也匹配15or 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有一个递归函数来实现这一点,但我认为它有点复杂。

4

4 回答 4

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

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

如果我误解了任何事情,请详细解释我您想要什么。

谢谢你

于 2013-09-26T18:28:05.880 回答
1

一个小提示:

/^1|3|5$/

方法

/^1//3//5$/

看。他们将帮助您确保交替的范围不包括您的开始/结束锚点。

于 2013-09-26T17:29:25.880 回答
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

where=> 0表示模式在第一个字符索引处匹配,并且nil未命中。

也就是说,我不会尝试使用模式来强制执行范围,因为那是试图使它们成为它们并不真正适合的东西。查看用于测试可接受的 IPv4 号码或更糟糕的IPv6号码的模式。为了真正有趣,请查看有效电子邮件地址的模式。它们都有定义什么是有效值的规范,但是定义这些值的模式很复杂,超出了凡人的理解范围。相反,使用模式来定位看起来像数字的东西,提取该值并测试它是否在可接受的范围内。

例如,这是来自 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 使其更加困难。有关详细信息,请参阅匹配有效 IPv6 地址的正则表达式。所以,我的建议是对简单的事情使用正则表达式,并利用它们的优势——提取与模式匹配的值,然后使用额外的代码来验证它们是否在范围内或真正有效。

于 2013-09-26T18:01:24.110 回答
0

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

于 2013-09-26T17:31:42.123 回答