正则表达式影响正则表达式后的内容

时间:2018-03-08 17:06:50

标签: regex sed non-greedy

我有一个包含以下文字的HTML文件:

<!doctype html><html><head><meta charset="utf-8"><title>Test</title><base href="/"><meta name="viewport" content="width=device-width,initial-scale=1"></head><body>test</body></html>

我对它运行sed命令:

sed -i -e "s:<base href\s*=\s*\".*\"\s*>:<base href=\"/apps/test/\">:g" /tmp/test/index.html

我希望只是将<base href="/">替换为<base href="/apps/test/">并将其余部分单独留下,但最终会影响正则表达式后的内容:

 <!doctype html><html><head><meta charset="utf-8"><title>Test</title><base href="/apps/test/"></head><body>test</body></html>

最终删除了正则表达式后找到的整个meta标记。我是不是正确地做了正则表达式?

GNU sed version 4.2.1

2 个答案:

答案 0 :(得分:2)

处理xml / html数据的唯一正确方法是使用xml / html解析器。

xmlstarlet 解决方案:

xmlstarlet fo -R -H /tmp/test/index.html | xmlstarlet ed -O -u '//base/@href' -v '/apps/test/'

输出:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8"/>
    <title>Test</title>
    <base href="/apps/test/"/>
    <meta name="viewport" content="width=device-width,initial-scale=1"/>
  </head>
  <body>test</body>
</html>

要就地修改文件,请添加-L选项:xmlstarlet ed -L -u ....

答案 1 :(得分:2)

由于*贪婪,.*中的=\s*\".*\"\s*>与最右边的>匹配。

您可以在命令周围使用单引号,这样就不必将\"用于双引号。然后,您可以使用".*"代替"[^"]*",而sed 's:<base href\s*=\s*"[^"]*"\s*>:<base href="/apps/test/">:g' 只匹配下一个双引号。

这会使你的命令进入

hxpipe

然而,使用sed和regexes操纵HTML总是很脆弱,并且会在第一个可能的机会中破解。您可以使用XML / HTML解析器,例如xmllint,请参阅Roman的答案;另一种选择是W3C HTML-XML-utils及其hxunpipe$ hxpipe infile.html !html "" (html (head Acharset CDATA utf-8 (meta (title -Test )title Ahref CDATA / (base Aname CDATA viewport Acontent CDATA width=device-width,initial-scale=1 (meta )head (body -test )body )html -\n 命令。

这些命令解析您的HTML并将其转换为使用sed,awk&amp; amp;朋友们,然后把它变回HTML:

/

所以要将href标记的base中的/apps/test/转换为$ hxpipe infile.html \ | sed '/Ahref CDATA/{N;/\n(base$/s|\(CDATA\) .*|\1 /apps/test/|}' \ | hxunpipe <!DOCTYPE html><html><head><meta charset="utf-8"><title>Test</title><meta href="/apps/test/" name="viewport" content="width=device-width,initial-scale=1"></head><body>test</body></html> ,我们可以这样做:

sed '/Ahref CDATA/{N;/\n(base$/s|\(CDATA\) .*|\1 /apps/test/|}'

其中sed命令

/Ahref CDATA/ {                                # If line matches this
    N                                          # Append next line
    /\n(base$/ s|\(CDATA\) .*|\1 /apps/test/|  # If in base tag, replace href
}

或更好的可读性

UPDATE contacts SET name = REPLACE(name, "ü", "ü")

以一种或多或少的强大方式进行改变。

相关问题