10

我正在阅读一个正则表达式组匹配问题,我看到有两种方法可以从正则表达式中引用捕获组,即,

  1. 匹配字符串方法例如string.match(/(^.*)(:)(.*)/i).captures
  2. Perl-esque 捕获组变量,例如 $1、$2 等,从if match =~ /(^.*)(:)(.*)/i
  3. 更新:正如 0xCAFEBABE 所提到的,还有第三个选项 - last_match方法

哪个更好?对于 1),为了安全起见,您将不得不使用 if 语句来防止出现 nil,那么为什么不直接提取信息呢?而不是调用字符串捕获方法的第二步。所以选项2)对我来说看起来更方便。

4

2 回答 2

18

从 v2.4.6 开始,Ruby 就有了named_captures,可以这样使用。只需?<some_name>在捕获组中添加语法。

/(\w)(\w)/.match("ab").captures # => ["a", "b"]
/(\w)(\w)/.match("ab").named_captures # => {}

/(?<some_name>\w)(\w)/.match("ab").captures # => ["a"]
/(?<some_name>\w)(\w)/.match("ab").named_captures # => {"some_name"=>"a"}

更相关的是,您可以按名称引用命名捕获!

result = /(?<some_name>\w)(\w)/.match("ab")
result["some_name"] # => "a" 
于 2019-12-30T12:19:47.263 回答
4

对于简单的任务,直接访问伪变量$1等可能更短更容易,但是当事情变得复杂时,通过MatchData实例访问事物是(几乎)唯一的方法。

例如,假设您正在执行嵌套gsub

string1.gsub(regex1) do |string2|
  string2.gsub(regex2) do
    ... # Impossible/difficult to refer to match data of outer loop
  end
end

在内部循环中,假设您想引用外部的捕获组gsub。调用$1,$2等不会给出正确的结果,因为最后一个匹配数据已通过执行内部gsub循环而更改。这将是错误的来源。

有必要通过匹配数据引用捕获的组:

string1.gsub(regex1) do |string2|
  m1 = $~
  string2.gsub(regex2) do
    m2 = $~
    ... # match data of the outer loop can be accessed via `m1`.
        # match data of the inner loop can be accessed via `m2`.
  end
end

简而言之,如果你想为简单的任务做一些简短的事情,你可以使用伪变量。如果你想让你的代码更加结构化和可扩展,你应该通过匹配数据来访问数据。

于 2013-07-19T10:57:17.170 回答