红宝石混淆中的正则表达式匹配

时间:2012-05-30 22:50:00

标签: ruby regex string string-matching

任何人都可以向我解释这个吗?

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 /)。首先返回["N/A"](和数组) 。为什么所有这些匹配都采取不同的行动?

2 个答案:

答案 0 :(得分:3)

来自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

     

匹配 - 如果 obj Regexp,请将其用作匹配 str 的模式,并返回匹配开始的位置,或{{ 1}}如果没有匹配。

所以当你说:

nil

str =~ /org-id:\s+(.+)\n/ 中的'org-id: N/A'$&中的'N/A',运算符的返回值为0;如果你的正则表达式中有另一个捕获组,你会在$1中看到该部分。 $2的“nil或不nil”返回值允许您说出以下内容:

=~

因此,make_pancakes_for($1) if(str =~ /some pattern that makes (us) happy/) 可以方便地一次性组合解析和布尔测试。


String#scan方法:

  

扫描(模式)→数组
  扫描(模式){|匹配,... | block}→str

     

两种形式都迭代 str ,匹配模式(可能是=~Regexp)。对于每个匹配,生成结果并将其添加到结果数组或传递给块。如果模式不包含组,则每个单独的结果由匹配的字符串String组成。如果模式包含组,则每个单独的结果本身就是一个包含每个组一个条目的数组。

因此$&为您提供了一个简单的匹配列表或匹配的AoA(如果涉及捕获组),scan意味着将一个字符串拆分为一次性的所有组件(排序)就像String#split)更复杂的版本。

如果您想从字符串中抓取所有scan个匹配项,请使用(.+)map

scan

但如果你知道array_of_ids = str.scan(/org-id:\s+(.+)\n/).map(&:first) 中会有几个org-id,你只会烦恼。扫描还会将str$&,...设置为$1中最后一场匹配的值;但如果你正在使用scan,你将会同时寻找几个匹配,所以这些全局变量不会非常有用。


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

答案 1 :(得分:0)

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