任何人都可以向我解释这个吗?
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"]
(和数组)。为什么所有这些匹配都表现不同?
来自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的模式,并返回匹配开始的位置,如果没有匹配则返回nil
。
所以当你说:
str =~ /org-id:\s+(.+)\n/
你得到'org-id: N/A'
的$&
,'N/A'
的$1
,运算符的返回值是零;如果你的正则表达式中有另一个捕获组,你会看到$2
中的那个部分。 nil
的“nil
或not =~
”返回值允许你说:
make_pancakes_for($1) if(str =~ /some pattern that makes (us) happy/)
所以=~
可以方便地一次性组合解析和布尔测试。
String#scan
方法:
扫描(模式)→数组 扫描(模式){|匹配,... |阻止}→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工作,除非在极端胁迫下,所以这没关系。
这是匹配和捕获之间的区别。 Str [regex]返回与整个正则表达式匹配的整个片段。 $ 1仅表示由first()子句捕获的匹配部分。