sed正则表达式在第一场比赛停止

时间:2012-06-09 20:43:57

标签: regex perl sed phpbb

我想替换以下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 = ...]标记中的第一个和最后一个匹配之间。我似乎无法让它取代行中这种模式的每一个出现...(我不认为有任何嵌套引号,但这会使它更加困难)

3 个答案:

答案 0 :(得分:3)

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

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

如果您有现有的 sed 脚本,则可以使用 s2p (1)实用程序将其转换为Perl。请注意,在Perl中,您确实希望在$1运算符的右侧使用s///。在大多数情况下,\1已经过时,但通常您需要$1

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

注意我已经删除了parens前面的反斜杠。使用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使得它将stdin,stdout和文件视为UTF-8。 -00使其在一次啜饮中读取整个文件,并且/s使点交叉换​​行边界。

答案 1 :(得分:1)

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

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

答案 2 :(得分: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]*代替.*全局替换换行符,然后替换剩余的换行符。 s/\n[^\n]*written by \([^\n]*\)<\/i>/[quote=\1]/g
  • 将未更改的换行符还原为原始前端模式。 s/\n/\<blockquote/g