带分组的正则表达式字符串?

时间:2014-02-24 16:59:21

标签: ruby regex grouping regex-group

我在文档中看到我能够做到:

/\$(?<dollars>\d+)\.(?<cents>\d+)/ =~ "$3.67" #=> 0
puts dollars #=> prints 3

我想知道这是否可行:

string = "\$(\?<dlr>\d+)\.(\?<cts>\d+)"
/#{Regexp.escape(string)}/ =~ "$3.67"

我明白了:

`<main>': undefined local variable or method `dlr' for main:Object (NameError)

1 个答案:

答案 0 :(得分:1)

你的方法有一些错误。首先,让我们看一下你的字符串:

string = "\$(\?<dlr>\d+)\.(\?<cts>\d+)"

您使用"\$"转义美元符号,但这与撰写"$"相同,请考虑:

"\$" == "$"
#=> true

要实际结束字符串“反斜杠后跟美元”,您需要写"\\$"。同样的事情适用于十进制字符类,您必须编写"\\d"以最终得到正确的字符串。

另一方面,问号实际上是正则表达式语法的一部分,所以你根本不想逃避它们。我建议对原始字符串使用单引号,因为这样可以使输入更容易:

string = '\$(?<dlr>\d+)\.(?<cts>\d+)'
#=> "\\$(?<dlr>\\d+)\\.(?<cts>\\d+)"

下一期是Regexp.escape。看看它用上面的字符串产生的正则表达式:

string = '\$(?<dlr>\d+)\.(?<cts>\d+)'
Regexp.escape(string)
#=> "\\\\\\$\\(\\?<dlr>\\\\d\\+\\)\\\\\\.\\(\\?<cts>\\\\d\\+\\)"

这是一个太多逃避的水平。当您想要匹配字符串中包含的文字字符时,可以使用Regexp.escape。例如,上面的转义正则表达式将匹配源字符串本身:

/#{Regexp.escape(string)}/ =~ string
#=> 0                                   # matches at offset 0

相反,您可以使用Regexp.new将源视为实际的正则表达式。

最后一个问题是如何访问匹配结果。显然,你得到的是NoMethodError。您可能认为匹配结果存储在名为dlrcts的局部变量中,但事实并非如此。您有两种方法可以访问匹配数据:

  • 使用Regexp.match,它将返回MatchData个对象
  • 使用regexp =~ string,然后使用全局变量$~
  • 访问最后一个匹配数据

我更喜欢前者,因为它更容易阅读。完整的代码将如下所示:

string = '\$(?<dlr>\d+)\.(?<cts>\d+)'
regexp = Regexp.new(string)

result = regexp.match("$3.67")
#=> #<MatchData "$3.67" dlr:"3" cts:"67">

result[:dlr]
#=> "3"

result[:cts]
#=> "67"