插入符在 Bash 正则表达式中不起作用?

Caret will not work in Bash regular expression?

我正在尝试匹配与 Markdown 文件中的图像位置相对应的行,因此我可以在适当的时候用数组中的值替换每个图像的地址。这些行看起来像这样:

![Alt text.](/!/image.jpg)

请注意,图片地址本身在括号内包含感叹号,因为这表示需要将其替换为真实地址。所以 image.jpg 充当我创建的数组的键。

假设键 image.jpg 的值为 http://images.com/an-example-image.jpg。我的 Bash 脚本的预期结果是:

![Alt text.](http://images.com/an-example-image.jpg) 

我一直在 Bash 中使用条件运算符来执行此操作...

testfile=$(<test-md.md)
re='(.*)\!(.*\()\/\!\/([0-9a-z\.\-]+)(\).*)'
while [[ $testfile =~ $re ]]; do
    testfile=${BASH_REMATCH[1]}"!"${BASH_REMATCH[2]}${imagemap[${BASH_REMATCH[3]}]}${BASH_REMATCH[4]}
done

到目前为止一切顺利。

但如果这些行是块引用或代码的一部分,我不想像这样捕获这些行,只有那些会被 Markdown 解析为实际图像的行。

我认为我可以通过坚持将开始图像放置的感叹号放在该行的最开头来避免这种情况。这是我试过的正则表达式:

re='(.*)^\!(.*\()\/\!\/([0-9a-z\.\-]+)(\).*)'

不幸的是,当我这样做时,Bash 似乎不想识别插入符号。替换仍然有效,但即使该行在代码中,它也会被替换。例如,这个 Markdown 文件:

![Alt text.](/!/image.jpg)

This image was placed with the following code:

    ![Alt text.](/!/image.jpg)

不幸变成这样:

![Alt text.](http://images.com/an-example-image.jpg)

This image was placed with the following code:

    ![Alt text.](http://images.com/an-example-image.jpg)

应该是这样的:

![Alt text.](http://images.com/an-example-image.jpg)

This image was originally placed with the following code:

    ![Alt text.](/!/image.jpg)

我也试过使用换行符 class 而不是插入符:

re='(.*)[\n\r]+\!(.*\()\/\!\/([0-9a-z\.\-]+)(\).*)'

这也不起作用,所以我可能是我错过了一些关于 Bash 正则表达式的重要信息。

在这种情况下我是否错误地使用了插入符?我如何才能仅捕获图像放置从行首开始的那些实例?

关于 downvoting 的风险,我建议您不要 使用正则表达式,因为 markdown 非常复杂。很有可能你总是会错过一些方面,例如反引号、代码环境、自定义 html 代码中的代码,...

然而,您可以使用 pandoc 将降价转换为更通用的格式,例如 html,然后使用 xmllint 捕获图像 url's :

pandoc -f markdown -t html | xmllint --html --xpath '//img/@src' -

如果您对给定的示例执行此操作,将得到:

$ echo '![Alt text.](/!/image.jpg)' | pandoc -f markdown -t html | xmllint --html --xpath '//img/@src' -
 src="/!/image.jpg"

pandoc 是一个旨在将所有类型的文档格式相互转换的程序。通过调用 pandoc -f markdown -t html,您将给定的 markdown 转换为 html。更容易解析的格式。

xmllint 是一个查询 xml 文档的程序。在这种情况下,我们提供了查询 //img/@src 表示:

Return all src attributes of all <img> tags in the input.

感谢评论中的 Avinsah Raj 为我提供了线索。起初我看不到它,但似乎没有办法让 Bash 正则表达式中的 Kleene 星号成为非贪婪的。 (如有错误,欢迎指正。)

我发现,如果我更改正则表达式,以便我们仅在第一个感叹号之后和左括号之前查找可打印字符,那么捕获就会起作用。它之前一定是太宽了,捕获换行符才能在先前不相关的行上找到较早的感叹号。

所以正确的正则表达式是:

re='(.*^\!\[[[:print:]]+\]\()\/\!\/([0-9a-z\.\-]+)(\).*)'

有了这个,插入符就可以工作了,只有行首的图像位置会被找到并相应地替换。

这让我整个下午都很生气,非常感谢 Avinsah!