Частичная замена gsub

Я хотел бы заменить в этом выражении только группу в скобках:

my_string.gsub(/<--MARKER_START-->(.)*<--MARKER_END-->/, 'replace_text')

так что я получаю: <--MARKER_START-->replace_text<--MARKER_END-->

Я знаю, что могу повторить все блоки MARKER_START и MARKER_END в выражении подстановки, но я подумал, что должен быть более простой способ сделать это.

Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Пошаговое руководство по созданию собственного Slackbot: От установки до развертывания
Шаг 1: Создание приложения Slack Чтобы создать Slackbot, вам необходимо создать приложение Slack. Войдите в свою учетную запись Slack и перейдите на...
19
0
6 787
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете сделать что-то вроде этого:

my_string.gsub(/(<--MARKER_START-->)(.*)(<--MARKER_END-->)/, 'replace_text')

Вам действительно нужен не жадный. * Совпадение там посередине. Смотри мой ответ

Orion Edwards 23.09.2008 07:32

Правда, вообще лучше бы не жадный матч. Я оставлю это на усмотрение Пьера, поскольку это может или не может быть применимо к его ситуации.

Greg Hewgill 23.09.2008 09:09

Я просто хочу добавить, что важно использовать одинарные кавычки (') в тексте замены (как в ответе). У меня возникли ошибки при использовании двойных кавычек (")

Redithion 28.08.2015 17:53

Вы можете сделать это с помощью утверждения просмотра вперед и назад с нулевой шириной.

Это регулярное выражение должно работать в ruby ​​1.9, perl и многих других местах:

Примечание. Ruby 1.8 поддерживает только утверждения с опережением. Чтобы сделать это правильно, вам нужно как смотреть вперед, так и назад.

 s.gsub( /(?<=<--MARKER START-->).*?(?=<--MARKER END-->)/, 'replacement text' )

Что происходит в Ruby 1.8, так это то, что ?<= вызывает сбой, потому что он не понимает утверждения о ретроспективе. Для этого вам нужно вернуться к использованию обратной ссылки, например Грейг Хьюгилл упоминает

так что вы получаете

 s.gsub( /(<--MARKER START-->).*?(?=<--MARKER END-->)/, 'replacement text' )

ОБЪЯСНЕНИЕ ПЕРВОЕ:

Я заменил (.)* в середине вашего регулярного выражения на .*? - это не жадно. Если у вас нет не жадного, то ваше регулярное выражение будет пытаться сопоставить столько, сколько может - если у вас есть 2 маркера в одной строке, это пойдет не так. Лучше всего это проиллюстрировать на примере:

"<b>One</b> Two <b>Three</b>".gsub( /<b>.*</b>/, 'BOLD' )
=> "BOLD"

Что мы на самом деле хотим:

"<b>One</b> Two <b>Three</b>".gsub( /<b>.*?</b>/, 'BOLD' )
=> "BOLD Two BOLD"

ПОЯСНЕНИЕ ВТОРОЕ:

Утверждение с нулевой шириной заглядывания в будущее звучит как гигантская куча ботанической путаницы.

На самом деле «прогнозируемое утверждение» означает: «Только совпадение, если то, что мы ищем, сопровождается другими вещами.

Например, соответствует цифре только в том случае, если за ней следует F.

"123F" =~ /\d(?=F)/ # will match the 3, but not the 1 or the 2

На самом деле «нулевая ширина» означает «учитывайте в нашем поиске ', за которым следует', но не учитывайте его как часть совпадения при замене, группировке или подобных вещах. Используя тот же пример 123F, если мы не использовали утверждение lookahead, а вместо этого просто сделаем это:

"123F" =~ /\dF/ # will match 3F, because F is considered part of the match

Как видите, это идеально подходит для проверки нашего <--MARKER END-->, но что нам нужно для <--MARKER START-->, так это возможность сказать: «Только совпадение, если то, что мы ищем, СЛЕДУЕТ за другими вещами». Это называется ретроспективным утверждением, которого в Ruby 1.8 нет по какой-то странной причине.

Надеюсь, это имеет смысл :-)

PS: Зачем использовать утверждения с опережением, а не просто обратные ссылки? Если вы используете опережающий просмотр, вы фактически не заменяете биты <--MARKER-->, а только содержимое. Если вы используете обратные ссылки, вы заменяете всю партию. Я не знаю, сильно ли это сказывается на производительности, но с точки зрения программирования это кажется правильным, поскольку на самом деле мы вообще не хотим заменять маркеры.

Отличный ответ, сохраняю на будущее :)

ndbroadbent 23.03.2012 18:31

Другие вопросы по теме