Замена частичных регулярных выражений на Ruby
Я хочу преобразовать следующий текст
This is a ![foto](foto.jpeg), here is another ![foto](foto.png)
на
This is a ![foto](/folder1/foto.jpeg), here is another ![foto](/folder2/foto.png)
другими словами, Я хочу найти все пути Изображения, заключенные в скобки (текст в синтаксисе Markdown), и заменить их другими путями. Строка, содержащая новый путь, возвращается отдельным .
Я хотел бы сделать это с помощью String#gsub
в его блочной версии. В настоящее время мой код выглядит так:
re = /![.*?]((.*?))/
rel_content = content.gsub(re) do |path|
real_path(path)
end
в проблема с этим регулярным выражением заключается в том, что оно будет соответствовать просто foto.jpeg
. Я также пробовал другие regexen, как (?>![.*?]()(.*?)(?>))
но безрезультатно.
мой текущий обходной путь-разделить путь и собрать его позже.
есть ли регулярное выражение Ruby, которое соответствует только пути внутри скобок, а не всем контекстным необходимым символам?
обновление после ответов: основная проблема здесь заключается в том, что Руби regexen нет никакого способа, чтобы указать нулевой ширины lookbehinds. Самое общее решение-сгруппировать то, что часть regexp до и после реальной совпадающей части, т. е. /(pre)(matching-part)(post)/
, а затем восстановите полную строку.
в этом случае решение должно быть
re = /(![.*?]()(.*?)())/
rel_content = content.gsub(re) do
+ real_path() +
end
3 ответов
быстрое решение (отрегулируйте по мере необходимости):
s = 'This is a ![foto](foto.jpeg)'
s.sub!(/!(\[.*?\])\((.*?)\)/, '(/folder1/)' )
p s # This is a [foto](/folder1/foto.jpeg)
вы всегда можете сделать это в два шага-сначала извлечь все выражение изображения, а затем второй заменить ссылку:
str = "This is a ![foto](foto.jpeg), here is another ![foto](foto.png)"
str.gsub(/\!\[[^\]]*\]\(([^)]*)\)/) do |image|
image.gsub(/(?<=\()(.*)(?=\))/) do |link|
"/a/new/path/" + link
end
end
#=> "This is a ![foto](/a/new/path/foto.jpeg), here is another ![foto](/a/new/path/foto.png)"
Я немного изменил первое регулярное выражение, но вы можете использовать то же самое, что и раньше. image
- это выражение изображения как ![foto](foto.jpeg)
и link
- это просто путь, как foto.jpeg
.
[EDIT] уточнение: у Ruby есть lookbehinds (и они используются в моем ответе):
вы можете создать lookbehinds С (?<=regex)
и (?<!regex)
для отрицательных, где regex
- произвольное выражение regex при соблюдении следующих условий. Выражения регулярных выражений в lookbehinds они должны быть фиксированной шириной из-за ограничений на реализацию регулярных выражений, что означает, что они не могут включать выражения с неизвестным количеством повторений или чередований с различными вариантами ширины. Если вы попытаетесь сделать это, вы получите ошибку. (Ограничение не распространяется на заглядывание вперед, хотя).
в вашем случае [foto]
часть имеет переменную ширину (foto
может быть любой строкой), поэтому он не может перейти в lookbehind из-за вышеизложенного. Однако lookbehind-это именно то, что нам нужно, поскольку это совпадение нулевой ширины, и мы используем это во втором регулярном выражении, которому нужно только беспокоиться о (фиксированной длине) обязательных открытых скобках.
очевидно, что вы можете поставить real_path
отсюда, но я просто хотел проверить пример.
I подумайте, что этот подход более гибкий и более читаемый, чем восстановление строки через переменные группы соответствия
в блоке, используйте для доступа к первой группе захвата (
для второго и так далее).
из документации:
в блочной форме текущая строка соответствия передается в качестве параметра и переменных, таких как $1, $2, $`, $&, и $ ' будет установлен соответствующим образом. Значение, возвращаемое блоком, будет заменено на совпадение при каждом вызове.