【问题标题】:How to match last occurrence in a string with Regex如何使用正则表达式匹配字符串中的最后一次出现
【发布时间】:2018-04-12 18:10:42
【问题描述】:

您好,我正在使用 ruby​​-2.5.0 和 Rails 5 开发 RoR 项目。我有一个从字符串中查找时间的模式,如下所示:-

time_pattern = /(\d{2}\:\d{2}:\d{2}|\d{2}\:\d{2})/
time = mystr[time_pattern]

它返回字符串中的第一个匹配时间,例如,如果字符串“14:04”和“14:05”中有两个时间,它将始终返回第一个“14:04”。我需要找到第二个。请帮助我使用正则表达式找到第二个匹配项。我也尝试过类似的扫描方法:-

time = params.to_s.scan(time_pattern).uniq.flatten.last

但我的 rubocop 抛出错误 Methods exceeded maximum allowed ABC complexity (1) 请帮忙。提前致谢。

【问题讨论】:

  • 可读性建议:\d\d\d{2} 相同,但缩短了 1 个字符 + 更易读 IMO。此外,您应该能够做到/\d\d\:\d\d(\:\d\d)?/(参见此处:rubular.com/r/UX13pdJZfm)。顺便说一句,使用这个正则表达式,99:99:99 匹配
  • @MrYoshiji 但在论点的另一边:\d\d 增加了不必要的计算,但是是的,您的第二部分要好得多\d{2}:\d{2}(?::\d{2})? 甚至\d{2}(?::\d{2}){1,2}。另外,: 不需要转义。
  • 使用scan,您需要具有非捕获组的版本,我会使用单词边界:params.to_s.scan(/\b\d{2}:\d{2}(?::\d{2})?\b/).uniq.flatten.last
  • 并回答如何匹配最后一次出现:params.to_s[/.*(\d{2}:\d{2}(?::\d{2})?)/, 1]
  • 它仍然返回第一个匹配项。请帮忙

标签: ruby-on-rails regex rubocop


【解决方案1】:

最后一个正则表达式匹配

要获得最后一场比赛,您只需在 #scan 结果上调用 #last

regex = /(\d{2}\:\d{2}:\d{2}|\d{2}\:\d{2})/ # original
# or
regex = /\d{2}(?::\d{2}){1,2}/ # kudos @ctwheels

string = '12:01, 12:02, 12:03:04, 12:05'

string.scan(regex).last
#=> "12:05"

ABC-公制

ABC 指标更复杂,需要查看您的整个方法。但这里有一篇博文解释得很好:Understanding Assignment Branch Condition

另一个选项是更改 RuboCop 设置中的最大 ABC 大小。查看RuboCop Configuration Documentationdefault configuration(Metrics/AbcSize 最大大小默认设置为 15)。

【讨论】:

  • 谢谢,但是当我最后使用扫描时,它会增加我的代码复杂性,因为我使用的是 rspec-rubocop。
  • @awsmsid string.scan(regex).last 只比string[regex] 多 1 个分支,这并不能胜任。此外,ABC 大小不取决于该单个调用,您还可以查看您的其他代码(在该方法中),看看是否有优化空间。或者可以将方法拆分为多个较小的方法。
【解决方案2】:

尝试使用以下表达式:/(\d{2}:\d{2}(:\d{2})?)/g

这是在ruby 中运行的示例:

re = /(\d{2}:\d{2}(:\d{2})?)/
str = ' "14:04" and "14:05"'

# Get matches
matches = str.scan(re)

# Get last match
matches = str.scan(re)

# Get last match
lastMatch = str.scan(re).last[0]

# Print last match
puts lastMatch.to_s
# OUTPUT => "14:05"

# Print the match result
str.scan(re) do |match|
    puts match.to_s
end

【讨论】:

  • @WiktorStribiżew 对不起,我更新了。我一直在看另一个 PHP 问题。
  • @Tony 虽然现在是 ruby​​,但它仍然不能回答 整个 问题。
  • @Tony 更好,不过你不需要转义 :
  • @Tony 我还建议删除捕获组:/\d{2}:\d{2}(?::\d{2})?/ 或打印将打印一个数组,而不仅仅是匹配的字符串。
  • 嘿,我的正则表达式正在工作,但它只返回字符串中的第一个匹配项,我想要字符串中的最后一个匹配项,请帮忙。我也试过 time = mystr[time_pattern] 但结果是一样的。
猜你喜欢
  • 2012-11-17
  • 1970-01-01
  • 1970-01-01
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多