Подтвердить что ты не робот

Частично заменить gsub

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

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

чтобы получить: <--MARKER_START-->replace_text<--MARKER_END-->

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Примечание: ruby ​​1.8 поддерживает только утверждения с открытым исходным кодом. Вам нужно как смотреть вперед, так и смотреть, чтобы сделать это правильно.

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

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

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

 s.gsub( /(<--MARKER START-->).*?(?=<--MARKER END-->)/, '\1replacement 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"

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

zero-width-look-ahead-assertion звучит как гигантская куча плотной путаницы.

То, что "look-ahead-assertion" на самом деле означает "Только совпадение, если вещь, которую мы ищем, сопровождается этим другим материалом.

Например, только соответствует цифре, если за ним следует 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: Зачем использовать утверждения lookahead вместо обратных ссылок? Если вы используете lookahead, вы фактически не заменяете биты <--MARKER-->, а только содержимое. Если вы используете обратные ссылки, вы заменяете всю партию. Я не знаю, наносит ли это большая часть производительности, но с точки зрения программирования кажется, что это правильно, поскольку мы фактически не хотим заменять маркеры вообще.