Ruby - 提取正则表达式捕获组的最佳方法?

时间:2013-07-19 10:26:23

标签: ruby regex

我正在阅读一个regex group matching问题,我发现有两种方法可以从正则表达式中引用捕获组,即

  1. Match字符串方法,例如string.match(/(^.*)(:)(.*)/i).captures
  2. if match =~ /(^.*)(:)(.*)/i
  3. 获取的Perl-esque捕获组变量,例如$ 1,$ 2等
  4. 更新:正如0xCAFEBABE所提到的,还有第三个选项 - last_match方法
  5. 哪个更好?使用1),为了安全起见,你必须使用if语句来防止nils,那么为什么不提取信息呢?而不是第二步调用字符串捕获方法。所以选项2)对我来说看起来更方便。

2 个答案:

答案 0 :(得分: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循环而发生了变化。这将是bug的来源。

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

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

简而言之,如果你想为简单的任务做短暂的hackish事情,你可以使用伪变量。如果您希望保持代码更加结构化和可扩展,则应通过匹配数据访问数据。

答案 1 :(得分:0)

忍不住想,目前接受的2013年答案已经过时。从2.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"