【问题标题】:Ruby Regexp group matching, assign variables on 1 lineRuby Regexp 组匹配,在 1 行上分配变量
【发布时间】: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)

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

【问题讨论】:

    标签: ruby regex pattern-matching


    【解决方案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://stackoverflow.com/a/21412455) 对这个问题有一个类似的早期答案。我不认为我在“偷窃”,但如果你想公平地表扬并尊重第一个答案,请随意:) 我希望没有动物受到伤害。

    【讨论】:

    • 这个答案看起来与stackoverflow.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 的原始正则表达式语法 :)
        猜你喜欢
        • 2013-08-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-24
        • 2017-02-11
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多