Ruby Regexp 组匹配,在 1 行上分配变量

Posted

技术标签:

【中文标题】Ruby Regexp 组匹配,在 1 行上分配变量【英文标题】:Ruby Regexp group matching, assign variables on 1 line 【发布时间】:2012-03-07 10:05:26 【问题描述】:

我目前正在尝试将字符串转换为多个变量。示例字符串:

ryan_string = "RyanOnRails: This is a test"

我已经将它与这个正则表达式匹配,有 3 个组:

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i)

现在要访问每个组,我必须执行以下操作:

ryan_group[0][0] (first group) RyanOnRails
ryan_group[0][1] (second group) :
ryan_group[0][2] (third group) This is a test

这看起来很荒谬,感觉就像我做错了什么。我希望能够做这样的事情:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)

这可能吗?或者有没有比我这样做更好的方法?

【问题讨论】:

【参考方案1】:

您必须决定这是否是一个好主意,但是 ruby​​ regexp 可以(自动)为您定义局部变量

我还不确定这个功能是真棒还是完全疯狂,但你的正则表达式可以定义局部变量。

ryan_string = "RyanOnRails: This is a test"
/^(?<webframework>.*)(?<colon>:)(?<rest>)/ =~ ryan_string
# This defined three variables for you. Crazy, but true.
webframework # => "RyanOnRails"
puts "W: #webframework , C: #colon, R: #rest"

(看看http://ruby-doc.org/core-2.1.1/Regexp.html,搜索“局部变量”)。

注意: 正如评论中所指出的,我看到@toonsend (https://***.com/a/21412455) 对这个问题有一个类似的早期答案。我不认为我在“偷窃”,但如果你想公平地表扬并尊重第一个答案,请随意:) 我希望没有动物受到伤害。

【讨论】:

这个答案看起来与***.com/a/21412455/525478 非常相似,后者早了一年多... @BradWerth 我想我只是没看到。但我更新了我的答案以包含您的疑虑。【参考方案2】:

您可以为捕获的匹配项命名

string = "RyanOnRails: This is a test"
/(?<one>^.*)(?<two>:)(?<three>.*)/i =~ string
puts one, two, three

如果你颠倒字符串和正则表达式的顺序,它就不起作用了。

【讨论】:

【参考方案3】:

你不希望 scan 这样做,因为它没有什么意义。您可以使用String#match,它将返回一个MatchData 对象,然后您可以调用#captures 返回一个捕获数组。像这样的:

#!/usr/bin/env ruby

string = "RyanOnRails: This is a test"
one, two, three = string.match(/(^.*)(:)(.*)/i).captures

p one   #=> "RyanOnRails"
p two   #=> ":"
p three #=> " This is a test"

请注意,如果未找到匹配项,String#match 将返回 nil,因此这样的操作可能会更好:

if match = string.match(/(^.*)(:)(.*)/i)
  one, two, three = match.captures
end

虽然scan 对此毫无意义。它仍然可以完成这项工作,您只需要先展平返回的 Array。 one, two, three = string.scan(/(^.*)(:)(.*)/i).flatten

【讨论】:

请注意,如果找不到匹配项,则 match 返回 nil 并且您会收到 NilError。如果你在 Rails,建议你把:one, two, three = string.match(/(^.*)(:)(.*)/i).captures 改成:one, two, three = string.match(/(^.*)(:)(.*)/i).try(:captures) @AndreaSalicetti 我已经编辑了我的帖子,我没有向其中添加特定于 Rails 的代码,所以我用处理返回的 nil 对象的版本对其进行了更改 您还可以使用新的&amp;. 运算符将其重新放在一条线上,甚至在只有一个捕获组时使用它两次。例如,string.match(regex)&amp;.captures&amp;.first【参考方案4】:

scan() 将在您的字符串中找到所有不重叠的正则表达式匹配项,因此它不会像您期望的那样返回一个组数组,而是返回一个数组数组。

您最好使用match(),然后使用MatchData#captures 获取捕获数组:

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures

但是,如果您愿意,也可以使用 scan() 执行此操作:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0]

【讨论】:

【参考方案5】:

您可以使用 Match 或 =~ 代替,这将为您提供一个匹配项,您可以以相同的方式访问匹配数据或仅使用特殊匹配变量 $1、$2、$3

类似:

if ryan_string =~ /(^.*)(:)(.*)/i
   first = $1
   third = $3
end

【讨论】:

@Gaston 这实际上是源自 Perl 的原始正则表达式语法 :)

以上是关于Ruby Regexp 组匹配,在 1 行上分配变量的主要内容,如果未能解决你的问题,请参考以下文章

ruby 正则表达式Regexp

RegExp

ruby 正则表达式

如何使用 regexp_replace 仅替换捕获组而不是完整匹配字符串

Oracle regexp_replace 挑选出模式匹配组

Ruby 超级不敏感的正则表达式将学校名称与口音和其他变音符号匹配