Ruby正则表达式问题与String上的sub方法有关

时间:2011-01-07 14:24:54

标签: ruby regex

我正在浏览Koans教程(这是一种很好的学习方法),我遇到了这样的说法:

assert_equal __, "one two-three".sub(/(t\w*)/) { $1[0, 1] }

在这个语句中,__是我应该把我期望的结果放到哪里以使测试正确执行的地方。我已经盯着它看了一段时间并把大部分分开了,但我无法弄清楚最后一点的含义:

{ $1[0, 1] }

预期的答案是:

"one t-three"

我期待着:

"t-t"

3 个答案:

答案 0 :(得分:11)

{ $1[0, 1] }是一个包含表达式$1[0,1]的块。 $1[0,1]计算字符串$1的第一个字符,其中包含最后一个匹配的正则表达式的第一个捕获组的内容。

当使用正则表达式和块调用sub时,它将找到正则表达式的第一个匹配项,调用该块,然后将匹配的子字符串替换为块的结果。

因此"one two-three".sub(/(t\w*)/) { $1[0, 1] }搜索模式t\w*。这会找到子串"two"。由于整个事物都在捕获组中,因此该子字符串存储在$1中。现在调用该块并返回"two"[0,1],即"t"。因此"two"已被"t"取代,您获得了"one t-three"

需要注意的一点是,与sub不同,gsub只会替换第一次出现,而不会出现模式。

答案 1 :(得分:3)

@ sepp2k已经给出了一个非常好的答案,我只想补充一下你如何使用IRB来自己实现目标:

>> "one two-three".sub(/(t\w*)/) { $1 } #=> "one two-three"
>> "one two-three".sub(/(t\w*)/) { $1[0] } #=> "one t-three"
>> "one two-three".sub(/(t\w*)/) { $1[1] } #=> "one w-three"
>> "one two-three".sub(/(t\w*)/) { $1[2] } #=> "one o-three"
>> "one two-three".sub(/(t\w*)/) { $1[3] } #=> "one -three"
>> "one two-three".sub(/(t\w*)/) { $1[0,3] } #=> "one two-three"
>> "one two-three".sub(/(t\w*)/) { $1[0,2] } #=> "one tw-three"
>> "one two-three".sub(/(t\w*)/) { $1[0,1] } #=> "one t-three"

答案 2 :(得分:1)

来自文档(http://ruby-doc.org/core/classes/String.html#M001185)的问题,这里是你的两个问题的答案“为什么返回值't-3'”和“$ 1 [0,1]}是什么意思?”

{$ 1 [0,1]}是什么意思? 方法String#sub可以使用两个参数,也可以使用一个参数和一个块。后者是这里使用的形式,它就像Integer.times方法一样,需要一个块:

5.times { puts "hello!" }

所以这解释了封闭的花括号。

$ 1是匹配正则表达式的第一个捕获组的子字符串,如here所述。 [0,1]是字符串方法“[]”,它根据数组值返回子字符串 - 这里是第一个字符。

放在一起,{$ 1 [0,1]}是一个返回$ 1中第一个字符的块,其中$ 1是当一个正则表达式最后一个用于匹配字符串时由捕获组匹配的子字符串。 / p>

为什么返回值为't三'? 方法String#sub('substitute')与其兄弟String#gsub('global substitute')不同,它将匹配正则表达式的字符串的第一部分替换为其替换。因此,该方法将用匹配“(t \ w *)”的第一个子串替换上述块的值 - 即用其第一个字符。由于'two'是第一个子串匹配(t \ w *)('t'后跟任意数量的字母),它被第一个字符't'取代。