Я нашел интересную вещь в рубине. Кто-нибудь знает, почему такое поведение?
попробовал '+'.gsub!('+', '\+')
и ожидал "\\+"
, но получил ""
(пустая строка)
PRD RSD, @tadman упомянул основные причины, по которым изображения кода не приветствуются в SO. Есть и другая причина: ссылки могут быть сломаны в будущем. Во многих случаях это сделало бы вопрос неполным; здесь урон меньше. Если вы используете только текст, вы можете быть уверены, что ваш полный вопрос навсегда останется в SO.
gsub
реализован, после некоторой косвенности, как rb_sub_str_bang в C, который вызывает rb_reg_regsub.
Теперь предполагается, что gsub
позволяет замещающей строке содержать обратные ссылки. То есть, если вы передаете регулярное выражение в качестве первого аргумента, и это регулярное выражение определяет группу захвата, тогда ваша строка замены может включать \1
, чтобы указать, что эта группа захвата должна быть помещена в эту позицию.
Такое поведение, очевидно, все еще происходит, если вы передаете обычную строку, не являющуюся регулярным выражением, в качестве шаблона. В вашей дословной строке, очевидно, не будет групп захвата, так что в данном случае это немного глупо. Но попытка заменить, например, +
на \1
в строке +
даст пустую строку, так как \1
говорит, что нужно перейти к первой группе захвата, которая не существует и, следовательно, бессодержательна ""
.
Теперь вы можете подумать: +
— это не число. И ты будешь прав. Вы заменяете +
на \+
. В вашей замещающей строке разрешено несколько других обратных ссылок. Я не смог найти никакой официальной документации, где это прописано, но исходный код работает вполне нормально. Подводя итог коду:
\1
до \9
относятся к пронумерованным группам захвата.\k<...>
относится к именованной группе захвата, имя которой заключено в угловые скобки.\0
или \&
относятся ко всей совпадающей подстроке, поэтому (\0)
в качестве строки замены будет заключать совпадение в круглые скобки.\'
относится ко всей строке после совпадения.\+
относится к последней группе захвата, то есть к группе с наибольшим номером.\\
— буквальная обратная косая черта.(Большинство из них основаны на переменных Perl с похожим именем)
Итак, в ваших примерах
\+
как говорится в заменяющей строке «взять последнюю группу захвата». Группы захвата нет, поэтому вы получаете пустую строку.\-
не является допустимой обратной ссылкой, поэтому она заменена дословно.\ok
также не является обратной ссылкой, поэтому заменено дословно.\\+
Ruby съедает первую последовательность обратной косой черты, поэтому фактическая строка во время выполнения — \+
, что эквивалентно первому примеру.\\\+
Ruby обрабатывает первую последовательность обратной косой черты, поэтому мы получаем \\+
к тому времени, когда функция замены ее увидит. \\
— это буквальная обратная косая черта, а +
больше не является частью escape-последовательности, поэтому мы получаем \+
.Вы можете сослаться на документ для String#gsub.
Вот «официальная документация», которую вы искали «Методы замены строк» и «Специальные глобальные переменные Regexp»
Обычно, когда публикуется подобное странное поведение, все недоумевают, пока кто-нибудь не объяснит, почему такое поведение на самом деле ожидается. Потом все кивают вертикально, одни хлопают себя по лбу, другие делают вывод, что ответ на самом деле очевиден, а иногда и говорят об этом в комментарии. (Я был озадачен, пока не прочитал ответ Сильвио и документ String#gsub.)