如何编写带有正则表达式和反向引用的Ruby switch语句(case…when)?


86

我知道我可以编写Ruby case语句来检查是否与正则表达式匹配。但是,我想在我的return语句中使用匹配数据。像这样的半伪代码:

foo = "10/10/2011"

case foo
    when /^([0-9][0-9])/
        print "the month is #{match[1]}"
    else
        print "something else"
end

我该如何实现?

谢谢!


请注意:我知道我不会在上述简单情况下使用switch语句,但这只是一个示例。实际上,我想要实现的是将许多可能的正则表达式与可以用各种方式编写的日期进行匹配,然后相应地使用Ruby的Date类进行解析。


1
Ruby的Date.parse可以理解许多日期格式。你试过了吗?
Raine 2011年

尽管它不能回答这个问题,但是您可能想看看慢性宝石……
DGM

Answers:


153

对最新正则表达式匹配组的引用始终存储在伪变量中, $1$9

case foo
when /^([0-9][0-9])/
    print "the month is #{$1}"
else
    print "something else"
end

您还可以使用$LAST_MATCH_INFO伪变量来获取整个MatchData对象。使用命名捕获时,这可能很有用:

case foo
when /^(?<number>[0-9][0-9])/
    print "the month is #{$LAST_MATCH_INFO['number']}"
else
    print "something else"
end

1
@Yossi您是否提供有关线程安全性的评论来源?我刚刚在ruby 1.8.7中进行了一项实验,似乎表明它是线程安全的!(线程每秒钟匹配一次正则表达式-检查irb是否破坏本地匹配项)
Joel

5
-1与正则表达式相关的变量不是全局变量,即使它前面带有美元符号也是如此。
安德鲁·格林

@AndrewGrimm感谢您指出这一点。我没有意识到。我必须更改很多旧代码:-/
Yossi

您也可以这样做$1$2...$9Regexp.last_match(1)按rubocop的建议进行
Edgar Ortega,

6

这是一种替代方法,可让您获得相同的结果,但不使用开关。如果将正则表达式放入数组中,则可以执行以下操作:

res = [ /pat1/, /pat2/, ... ]
m   = nil
res.find { |re| m = foo.match(re) }
# Do what you will with `m` now.

m在该块外部声明之后,它在find完成该块之后仍然可以使用,并且find将在该块返回真值后立即停止,因此您将获得与开关相同的快捷方式行为。MatchData如果需要,这可以为您提供完整的信息(也许您想在正则表达式中使用命名的捕获组),并且可以很好地将正则表达式与搜索逻辑分开(这可能会或可能不会产生更清晰的代码),甚至可以从配置文件或在运行时选择所需的一组。


我也在考虑使用该case方法的线程安全性。也许您想在线程化方案中使用mu方法,而不是在case方法中使用全局变量(?)
Casper
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.