【问题标题】:Can sed regex simulate lookbehind and lookahead?sed 正则表达式可以模拟后视和前瞻吗?
【发布时间】:2013-01-30 23:22:24
【问题描述】:

我正在尝试编写一个 sed 脚本,它将捕获文本文件中的所有“裸”URL 并将它们替换为 <a href=[URL]>[URL]</a>。 “裸”是指未包含在锚标记内的 URL。

我最初的想法是我应该匹配前面没有 " 或 > 并且后面也没有

示例输入:

[Beginning of File]http://foo.bar arbitrary text
http://test.com other text
<a href="http://foobar.com">http://foobar.com</a>
Nearing end of file!!! http://yahoo.com[End of File]

期望的输出样本:

[Beginning of File]<a href="http://foo.bar">http://foo.bar</a> arbitrary text
<a href="http://test.com">http://test.com</a> other text
<a href="http://foo.bar">http://foo.bar</a>
Nearing end of file!!! <a href="http://yahoo.com">http://yahoo.com</a>[End of File]

注意第三行没有被修改,因为它已经在&lt;a href&gt; 中。 另一方面,第一行和第二行都被修改了。 最后,观察所有非 URL 文本都没有被修改。

最终,我正在尝试做类似的事情:

sed s/[^>"](http:\/\/[^\s]\+)/<a href="\1">\1<\/a>/g 2-7-2013

我首先验证以下内容是否正确匹配并删除 URL:

sed 's/http:\/\/[^\s]\+//g'

然后我尝试了这个,但它无法匹配从文件/输入开头开始的 URL:

sed 's/[^\>"]http:\/\/[^\s]\+//g'

有没有办法在 sed 中解决这个问题,或者通过模拟后向/前瞻,或者显式匹配文件开头和文件结尾?

【问题讨论】:

  • 你为什么用[^\&gt;"]
  • 我正在寻找一个前面没有引号或大于号的 URL。
  • 感谢关于不转义的说明。
  • 更新您的问题以显示一些具有代表性的示例输入和给定该输入的预期输出 - 这对我们来说比您尝试过的更重要(尽管这也很有用)。
  • @EdMorton,观察问题已更新为样本输入和输出。

标签: regex sed awk regex-negation regex-lookarounds


【解决方案1】:

sed 是用于在单行上进行简单替换的出色工具,对于任何其他文本操作问题,只需使用 awk。

检查我在下面的 BEGIN 部​​分中使用的定义,以获取匹配 URL 的正则表达式。它适用于您的示例,但我不知道它是否捕获所有可能的 URL 格式。即使它可能不足以满足您的需求。

$ cat file
[Beginning of File]http://foo.bar arbitrary text
http://test.com other text
<a href="http://foobar.com">http://foobar.com</a>
Nearing end of file!!! http://yahoo.com[End of File]
$
$ awk -f tst.awk file
[Beginning of File]<a href="http://foo.bar">http://foo.bar</a> arbitrary text
<a href="http://test.com">http://test.com</a> other text
<a href="http://foobar.com">http://foobar.com</a>
Nearing end of file!!! <a href="http://yahoo.com">http://yahoo.com</a>[End of File]
$
$ cat tst.awk
BEGIN{ urlRe="http:[/][/][[:alnum:]._]+" }
{
    head = ""
    tail = $0
    while ( match(tail,urlRe) ) {
       url  = substr(tail,RSTART,RLENGTH)
       href = "href=\"" url "\""

       if (index(tail,href) == (RSTART - 6) ) {
          # this url is inside href="url" so skip processing it and the next url match.
          count = 2
       }

       if (! (count && count--)) {
          url = "<a " href ">" url "</a>"
       }

       head = head substr(tail,1,RSTART-1) url
       tail = substr(tail,RSTART+RLENGTH)
    }

    print head tail
}

【讨论】:

  • 在 url 正则表达式中,您使用 _ 作为有效的主机名字符,不应该是 - 吗?
  • 正如我在答案顶部所说的Check the definition I'm using in the BEGIN section below for a regexp that matches URLs. It works for your sample but I don't know if it captures all possible URL formats.。我不是 URL 语法专家。
【解决方案2】:

你的命令明显的问题是

You did not escape the parenthesis "("

这是sed 正则表达式的奇怪之处。与 Perl 正则表达式不同的是,许多符号默认为“文字”。您必须将它们转义为“功能”。试试:

s/\([^>"]\?\)\(http:\/\/[^\s]\+\)/\1<a href="\2">\2<\/a>/g

【讨论】:

  • 澄清一下,我正在尝试匹配前面没有 " 或 > 的 URL。
  • 给定的解决方案将不匹配文件开头或输入开头的http://google.com
  • @merlin2011 我明白你的意思了。 sed 不支持向前/向后看,我只是编辑过。问号使其可选
  • 关于奇怪的\(,一个选项是使用sed -r,这样(就不需要被引用了。 (我什至有一个rsed 别名)
  • @texasbruce,当您将其设为可选时,它现在的效果是它将匹配&lt;a href= 内的 URL,这不是本意。
猜你喜欢
  • 2015-09-13
  • 1970-01-01
  • 2013-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-11
  • 1970-01-01
  • 2014-07-05
相关资源
最近更新 更多