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 对象的版本对其进行了更改
您还可以使用新的&.
运算符将其重新放在一条线上,甚至在只有一个捕获组时使用它两次。例如,string.match(regex)&.captures&.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 行上分配变量的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 regexp_replace 仅替换捕获组而不是完整匹配字符串