用Ruby替换部分正则表达式匹配

gio*_*ele 8 ruby regex markdown replace

我想转换以下文字

This is a ![foto](foto.jpeg), here is another ![foto](foto.png)
Run Code Online (Sandbox Code Playgroud)

This is a ![foto](/folder1/foto.jpeg), here is another ![foto](/folder2/foto.png)
Run Code Online (Sandbox Code Playgroud)

换句话说,我想找到括在括号中的所有图像路径(文本采用Markdown语法),并用其他路径替换它们.包含新路径的字符串由单独的real_path函数返回.

我想String#gsub在它的块版本中使用它.目前我的代码如下所示:

re = /!\[.*?\]\((.*?)\)/

rel_content = content.gsub(re) do |path|
    real_path(path)
end
Run Code Online (Sandbox Code Playgroud)

这个正则表达式的问题在于它将匹配![foto](foto.jpeg)而不仅仅是foto.jpeg.我也试过其他regexen,(?>\!\[.*?\]\()(.*?)(?>\))但无济于事.

我目前的解决方法是拆分路径并稍后重新组装.

是否有一个Ruby正则表达式只匹配括号内的路径而不是所有上下文所需的字符?

答案后更新:这里的主要问题是Ruby的regexen没有办法指定零宽度的lookbehinds.最通用的解决方案是将regexp之前的部分和实际匹配部分之后的部分分组,即/(pre)(matching-part)(post)/,然后重建完整的字符串.

在这种情况下,解决方案将是

re = /(!\[.*?\]\()(.*?)(\))/

rel_content = content.gsub(re) do
    $1 + real_path($2) + $3
end
Run Code Online (Sandbox Code Playgroud)

Mar*_*oda 7

快速解决方案(根据需要进行调整):

s = 'This is a ![foto](foto.jpeg)'

s.sub!(/!(\[.*?\])\((.*?)\)/, '\1(/folder1/\2)' )

p s  # This is a [foto](/folder1/foto.jpeg)
Run Code Online (Sandbox Code Playgroud)


Car*_*ter 5

您始终可以分两步完成 - 首先提取整个图像表达式,然后替换链接:

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)"
Run Code Online (Sandbox Code Playgroud)

我对第一个正则表达式做了一些更改,但是您可以使用之前的正则表达式来代替它。image是图像表达![foto](foto.jpeg)link是路径foto.jpeg

[编辑]澄清:Ruby确实有lookbehinds(它们在我的答案中使用):

您可以使用 for Positive 和 for Negative 创建后向查找,其中满足以下条件的任意正则表达式。由于正则表达式实现的限制,lookbehind 中的正则表达式必须是固定宽度的,这意味着它们不能包含具有未知数量的重复或具有不同宽度选择的交替的表达式。如果您尝试这样做,您会收到错误。(但该限制不适用于前瞻)。(?<=regex)(?<!regex)regex

在您的情况下,该[foto]部分具有可变宽度(foto可以是任何字符串),因此它不能由于上述原因而进入向后查找。然而,lookbehind 正是我们所需要的,因为它是零宽度匹配,并且我们在第二个正则表达式中利用了这一点,它只需要担心(固定长度)强制左括号。

显然你可以real_path从这里输入,但我只是想要一个可测试的例子。

我认为这种方法比通过匹配组变量重建字符串更灵活,更具可读性