【问题标题】:regex matching in ruby confusion红宝石混淆中的正则表达式匹配
【发布时间】:2012-06-05 05:22:54
【问题描述】:

谁能给我解释一下?

str = "org-id:         N/A\n"

puts str[/org-id:\s+(.+)\n/]
=> "org-id:         N/A\n"
str =~ /org-id:\s+(.+)\n/
puts $1
=> "N/A"

我只需要

str =~ /org-id:\s+(.+)\n/
puts $1

在一行中。 但是 str[/org-id:\s+(.+)\n/]str.slice(/org-id:\s+(.+)\n/) 返回 "org-id: N/A\n" 和 str.scan(/org-id:\s+(.+)\n/).first 返回 ["N/A"] (和数组)。为什么所有这些匹配的行为不同?

【问题讨论】:

    标签: ruby regex string string-matching


    【解决方案1】:

    这是匹配和捕获之间的区别。 Str[regex] 返回与整个正则表达式匹配的整个片段。 $1 仅代表第一个 () 子句捕获的匹配部分。

    【讨论】:

      【解决方案2】:

      来自fine manual

      str[regexp] → new_str 或 nil
      str[regexp, fixnum] → new_str 或 nil

      如果提供了Regexp,则返回str 的匹配部分。如果数字或名称参数跟随正则表达式,则返回 MatchData 的那个组件。

      因此,如果您执行str[/org-id:\s+(.+)\n/],那么您将获得整个匹配部分(AKA $&);如果你想要第一个捕获组(AKA $1),那么你可以说:

      puts str[/org-id:\s+(.+)\n/, 1]
      # 'N/A'
      

      如果您的正则表达式中有第二个捕获组并且您想要它捕获的内容,您可以说str[regex, 2] 等等。因此,您也可以使用命名的捕获组和符号:

      puts str[/org-id:\s+(?<want>.+)\n/, :want]
      

      因此,使用正确的模式和参数,String#[] 可以方便地从字符串中提取单个基于正则表达式的块。

      如果您查看手册,您应该注意到String#[]String#splice 是同一个东西。


      如果我们查看String#=~,我们会看到:

      str =~ obj → fixnum 或 nil

      Match——如果 objRegexp,则将其用作匹配 str 的模式,并返回匹配开始的位置,或者 nil 如果没有匹配项。

      所以当你说:

      str =~ /org-id:\s+(.+)\n/
      

      你在$&amp;中得到'org-id: N/A',在$1中得到'N/A',运算符的返回值是数字零;如果您的正则表达式中有另一个捕获组,您会在$2 中看到该部分。 =~ 的“nil or not nil”返回值允许你说:

      make_pancakes_for($1) if(str =~ /some pattern that makes (us) happy/)
      

      所以=~ 便于一次性结合解析和布尔测试。


      String#scan 方法:

      scan(pattern) → 数组
      scan(pattern) {|match, ...|块 } → str

      两种形式都遍历str,匹配模式(可能是RegexpString)。对于每个匹配,都会生成一个结果并将其添加到结果数组或传递给块。如果模式不包含任何组,则每个单独的结果都包含匹配的字符串$&amp;。如果模式包含组,则每个单独的结果本身就是一个数组,每个组包含一个条目。

      所以scan 为您提供了一个简单的匹配列表或匹配的 AoA(如果涉及捕获组),scan 旨在一次将一个字符串拆分为所有组成部分(有点像更复杂的String#split 的版本)。

      如果您想从字符串中获取所有 (.+) 匹配项,您可以使用 scanmap

      array_of_ids = str.scan(/org-id:\s+(.+)\n/).map(&:first)
      

      但如果您知道str 中会有多个 org-id,您只会为此烦恼。扫描还会将$&amp;$1、...设置为scan 中最后一个匹配项的值;但如果您使用的是scan,您将同时查找多个匹配项,因此这些全局变量不会非常有用。


      三种正则表达式方法([]=~scan)提供了类似的功能,但它们填补了不同的领域。你可以用scan 来做这一切,但这将是毫无意义的麻烦,除非你是一个正交偏执狂,然后你肯定不会在 Ruby 中工作,除非在极端的胁迫下,所以这无关紧要。

      【讨论】:

        猜你喜欢
        • 2019-04-22
        • 1970-01-01
        • 2022-06-23
        • 1970-01-01
        • 2016-12-14
        • 2011-10-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多