4

我想替换以下 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=...] 标记中。我似乎无法让它替换行中这种模式的每一次出现......(我认为没有任何嵌套引号,但这会使它变得更加困难)

4

3 回答 3

3

您需要一个使用 Perl 兼容的正则表达式的sed (1) 版本,以便您可以做一些事情,比如进行最小匹配,或者一个带有负前瞻的匹配。

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

如果您有一个现有的sed脚本,您可以使用s2p (1) 实用程序将其转换为 Perl 。请注意,在 Perl 中,您确实希望$1在运算符的右侧使用s///。在大多数情况下,它\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使点越过换行符边界。

于 2012-06-09T21:03:19.250 回答
1

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

perl -pe 's/<blockquote.*?written by \(.*\)<\/i>/[quote=\1]/g' filename
于 2012-06-09T20:50:46.007 回答
0

这可能对您有用:

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]*使用 a而不是全局替换换行符,然后是剩余的模式.*s/\n[^\n]*written by \([^\n]*\)<\/i>/[quote=\1]/g
  • 将那些未更改的换行符恢复为原始的前面模式。s/\n/\<blockquote/g
于 2012-06-09T21:41:11.357 回答