来自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——如果 obj 是 Regexp,则将其用作匹配 str 的模式,并返回匹配开始的位置,或者 nil 如果没有匹配项。
所以当你说:
str =~ /org-id:\s+(.+)\n/
你在$&中得到'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,匹配模式(可能是Regexp 或String)。对于每个匹配,都会生成一个结果并将其添加到结果数组或传递给块。如果模式不包含任何组,则每个单独的结果都包含匹配的字符串$&。如果模式包含组,则每个单独的结果本身就是一个数组,每个组包含一个条目。
所以scan 为您提供了一个简单的匹配列表或匹配的 AoA(如果涉及捕获组),scan 旨在一次将一个字符串拆分为所有组成部分(有点像更复杂的String#split 的版本)。
如果您想从字符串中获取所有 (.+) 匹配项,您可以使用 scan 和 map:
array_of_ids = str.scan(/org-id:\s+(.+)\n/).map(&:first)
但如果您知道str 中会有多个 org-id,您只会为此烦恼。扫描还会将$&、$1、...设置为scan 中最后一个匹配项的值;但如果您使用的是scan,您将同时查找多个匹配项,因此这些全局变量不会非常有用。
三种正则表达式方法([]、=~ 和 scan)提供了类似的功能,但它们填补了不同的领域。你可以用scan 来做这一切,但这将是毫无意义的麻烦,除非你是一个正交偏执狂,然后你肯定不会在 Ruby 中工作,除非在极端的胁迫下,所以这无关紧要。