Вопрос о регулярных выражениях в Ruby относительно метода sub в String - PullRequest
5 голосов
/ 07 января 2011

Я бегу по учебнику по Коанам (это отличный способ учиться), и я столкнулся с этим утверждением:

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

В этом утверждении __ - это то место, куда я должен поместить ожидаемый результат, чтобы тест выполнялся правильно. Я смотрел на это некоторое время и вытащил большую часть этого на части, но я не могу понять, что означает последний бит:

{ $1[0, 1] }

Ожидаемый ответ:

"one t-three"

и я ожидал:

"t-t"

Ответы [ 3 ]

11 голосов
/ 07 января 2011

{ $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, заменяет только первое вхождение, а не вхождение шаблона.

3 голосов
/ 07 января 2011

@ 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"
1 голос
/ 07 января 2011

Извлечение из документации (http://ruby -doc.org / core / classes / String.html # M001185 ), вот ответы на два ваших вопроса: «почему возвращаемое значение» один ттри «» и «что означает {$ 1 [0, 1]}?»

Что означает {$ 1 [0, 1]}? Метод String # sub может принимать либодва аргумента или один аргумент и блок.Последняя является формой, используемой здесь, и она похожа на метод Integer.times, который принимает блок:

5.times { puts "hello!" }

Так что это объясняет вьющиеся фигурные скобки.

$ 1 - это подстрокасоответствие первой группе захвата регулярного выражения, как описано здесь .[0, 1] - это строковый метод "[]", который возвращает подстроку, основанную на значениях массива - здесь, первый символ.

Если собрать вместе, {$ 1 [0, 1]} - это блок, которыйвозвращает первый символ в $ 1, где $ 1 - это подстрока, которая должна соответствовать группе захвата, когда регулярное выражение использовалось в последний раз для сопоставления со строкой.

Почему возвращаемое значение 'один t-три'? Метод String # sub (' substitute '), в отличие от своего брата String # gsub (' глобально заменитель '), заменяет первую часть строки, соответствующую регулярному выражению, его заменой.Следовательно, метод заменит первую подстроку, соответствующую «(t \ w *)», значением блока, описанного выше, то есть его первым символом.Поскольку 'two' - это первое совпадение подстроки (t \ w *) (за "t" следует любое количество букв), оно заменяется первым символом, "t".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...