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

rya*_*nes 115 ruby regex pattern-matching

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

ryan_string = "RyanOnRails: This is a test"
Run Code Online (Sandbox Code Playgroud)

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

ryan_group = ryan_string.scan(/(^.*)(:)(.*)/i)
Run Code Online (Sandbox Code Playgroud)

现在要访问每个组,我必须做这样的事情:

ryan_group[0][0] (first group) RyanOnRails
ryan_group[0][1] (second group) :
ryan_group[0][2] (third group) This is a test
Run Code Online (Sandbox Code Playgroud)

这看起来很荒谬,感觉我做错了.我希望能够做到这样的事情:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)
Run Code Online (Sandbox Code Playgroud)

这可能吗?还是有比我做得更好的方式?

Lee*_*vis 186

你不想要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"
Run Code Online (Sandbox Code Playgroud)

请注意,如果找不到匹配项,String#match则返回nil,这样的事情可能会更好:

if match = string.match(/(^.*)(:)(.*)/i)
  one, two, three = match.captures
end
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,如果未找到匹配项,则匹配返回nil,您将获得NilError.如果你在Rails中,我建议你改变:`one,two,three = string.match(/(^.*)(:)(.*)/ i).captures` into:`one,two,three = string.match(/(^.*)(:)(.*)/ i).try(:captures)` (6认同)
  • @AndreaSalicetti我编辑了我的帖子,我没有添加特定于Rails的代码,所以我用一个处理返回的nil对象的版本对其进行了修改 (5认同)
  • 您还可以使用新的"&."运算符将其恢复为一行,甚至在只有一个捕获组时使用它两次.例如..,`string.match(正则表达式)&.捕获&.first` (2认同)

Rad*_*ado 41

您可以使用Match或=〜而不是一个匹配,您可以以相同的方式访问匹配数据,或者只使用特殊匹配变量$ 1,$ 2,$ 3

就像是:

if ryan_string =~ /(^.*)(:)(.*)/i
   first = $1
   third = $3
end
Run Code Online (Sandbox Code Playgroud)

  • @Gaston实际上是源自Perl的原始regexp语法:) (4认同)

小智 27

您可以为捕获的匹配命名

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

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


And*_*ark 6

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

您可能最好使用match(),然后使用MatchData#captures以下方法获取捕获数组:

g1, g2, g3 = ryan_string.match(/(^.*)(:)(.*)/i).captures
Run Code Online (Sandbox Code Playgroud)

但是,scan()如果您想这样做,您也可以这样做:

g1, g2, g3 = ryan_string.scan(/(^.*)(:)(.*)/i)[0]
Run Code Online (Sandbox Code Playgroud)


Fel*_*lix 6

您必须确定这是否是一个好主意,但是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}"
Run Code Online (Sandbox Code Playgroud)

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

注意: 正如评论中指出的那样,我看到@toonsend(/sf/answers/1498871881/)对这个问题有一个类似的较早答案。我不认为我在“偷”东西,但是如果您想对自己的称赞和荣誉感到公平,请放心:)我希望没有动物受到伤害。