【问题标题】:sed regex stop at first matchsed 正则表达式在第一场比赛中停止
【发布时间】:2012-06-09 20:43:56
【问题描述】:

我想替换以下 html 文本的一部分(一个大文件的摘录),以将旧的论坛格式(由于 2 年前完成的非常糟糕的论坛移植工作导致)更新为常规的 phpBB 格式:

    <blockquote id="quote"><font size="1" face="Verdana, Arial, Helvetica" id="quote">quote:<hr height="1" noshade id="quote"><i>written by User</i>

这应该被过滤成:

    [quote=User]

我在 sed 中使用了以下正则表达式

    s/<blockquote.*written by \(.*\)<\/i>/[quote=\1]/g

这适用于给定的示例,但在实际文件中,这样的几个引号可以在一行中。在那种情况下,sed 太贪心了,将第一个和最后一个匹配项之间的所有内容都放在 [quote=...] 标记中。我似乎无法让它替换行中这种模式的每一次出现......(我认为没有任何嵌套引号,但这会使它变得更加困难)

【问题讨论】:

  • sed 使用 Perl 正则表达式:ssed

标签: regex perl sed phpbb


【解决方案1】:

您需要一个使用与 Perl 兼容的正则表达式的 sed(1) 版本,以便您可以执行诸如进行最小匹配或具有否定前瞻的匹配等操作。

最简单的方法就是首先使用 Perl。

如果您有一个现有的 sed 脚本,您可以使用 s2p(1) 实用程序将其转换为 Perl。请注意,在 Perl 中,您确实希望在 s/// 运算符的右侧使用 $1。在大多数情况下,\1 是祖父的,但一般情况下你希望$1 存在:

s/<blockquote.*?written by (.*?)<\/i>/[quote=$1]/g;

请注意,我已经删除了括号前面的反斜杠。使用 Perl 的另一个优点是它使用了正常的 egrep 风格的正则表达式(如 awk),而不是丑陋的 grep 风格的正则表达式(如sed),它需要所有那些令人困惑(和不一致)的反斜杠。

使用 Perl 的另一个优点是您可以使用成对的、可嵌套的分隔符来避免难看的反斜杠。例如:

s{<blockquote.*?written by (.*?)</i>}
 {[quote=$1]}g;

其他优点包括 Perl 与 UTF-8(现在是 Web 的多数编码形式)非常好相处,并且您可以进行多行匹配,而不会像 sed 那样感到极度痛苦。例如:

$ perl -CSD -00 -pe 's{<blockquote.*?written by (.*?)</i>}{[quote=$1]}gs' file1.utf8 file2.utf8 ...

-CSD 使其将标准输入、标准输出和文件视为 UTF-8。 -00 使其一口气读取整个文件,/s 使点根据需要跨越换行符边界。

【讨论】:

  • 太棒了!有趣的是,我一开始是使用 Perl,但因为据说它要快得多,所以我被引诱使用 sed……不知道它在这方面是如此有限。不确定 -00 是否是个好主意,因为它是一个 500M 的文件(包含 html 的 sql,我在第一篇文章中不完整)。非常感谢!!!
【解决方案2】:

我不认为sed 支持非贪婪匹配。你可以试试 perl:

perl -pe 's/<blockquote.*?written by \(.*\)<\/i>/[quote=\1]/g' filename

【讨论】:

  • 好主意,但这不会像你那样工作:你忘了切换到 egrep 样式的模式,反斜杠更少,所以你没有捕获任何事物。看我的回答。
【解决方案3】:

这可能对你有用:

sed '/<blockquote.*written by .*<\/i>/!b;s/<blockquote/\n/g;s/\n[^\n]*written by \([^\n]*\)<\/i>/[quote=\1]/g;s/\n/\<blockquote/g' file

解释:

  • 如果一行不包含该模式,则跳过它。 /<blockquote.*written by .*<\/i>/!b
  • 在整个行中全局将模式的前面更改为换行符。 s/<blockquote/\n/g
  • 使用[^\n]* 而不是.* 全局替换换行符,然后是剩余模式。 s/\n[^\n]*written by \([^\n]*\)<\/i>/[quote=\1]/g
  • 将那些未更改的换行符恢复为原始的前面模式。 s/\n/\<blockquote/g

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-24
    • 2018-07-26
    • 2016-11-18
    相关资源
    最近更新 更多