使用SED(或类似的东西)编辑多个HTML文件

时间:2010-07-16 00:09:58

标签: html sed

我有大约1000个要编辑的HTML文件,它们代表了大型技术文档中的脚注。我被要求逐个浏览HTML文件并手动编辑HTML,以便直接和缩小。

我知道这可能在几秒钟内用SED完成,因为每个文件的更改都是相似的。每个文件中的正文文本可以不同,但​​我想更改标记以匹配以下内容:

<body>
<p class="Notes">See <i>R v Swain</i> (1992) 8 CRNZ 657 (HC).</p>
</body>

文本可能会改变,例如,它可能会说'看 Pinky和大脑(1992)或类似的东西,但基本上正文应该是那样。

但是,目前正文可能是:

<body>
<p class="Notes"><span class="FootnoteReference"><span lang="EN-GB" xml:lang="EN-GB"><span><span 
  class="FootnoteReference"><span lang="EN-GB" xml:lang="EN-GB" style="font-size: 10.0pt;">See <i>R v Pinky and the Brain</i> (1992) </span></span></span></span></span></p>
</body>

甚至:

<body>
<p class="FootnoteText"><span class="FootnoteReference"><span lang="EN-US" 
  xml:lang="EN-US" style="font-size: 10.0pt;"><span><![endif]></span></span></span>See <i>R v Pinky and the Brain</i> (1992)</p>
</body>

任何人都可以建议一个SED表达式或类似的东西来解决这个问题吗?

5 个答案:

答案 0 :(得分:0)

喜欢这个?:

perl -pe 's/Swain/Pinky and the Brain/g;' -i lots.html of.html files.html

细分:

  • -e =“在命令行上使用代码”
  • -p =“在每个文件的每一行执行代码,并打印出该行,包括更改的内容”
  • -i =“实际上用新内容替换文件”

如果您将-i换成-i.old,则lot.html.old和of.html.old(等)将包含更改前的文件,以防您需要返回。< / p>

这将在所有文件中仅用Swain替换Pinky and the Brain。进一步的更改将需要更多的命令运行。或者:

s/Swain/Pinky/g; s/Twain/Brain/g;

将Swain与Pinky和Twain交换到大脑无处不在。

更新

如果您可以确定数据的传入格式,那么这样的事情就足够了:

# cat ff.html
  <body>
  <p class="Notes"><span class="FootnoteReference"><span lang="EN-GB" xml:lang="EN-GB"><span><span 
    class="FootnoteReference"><span lang="EN-GB" xml:lang="EN-GB" style="font-size: 10.0pt;">See <i>R v Twain</i> (1992) </span></span></span></span></span></p>
  <p class="Notes"><span class="FootnoteReference"><span lang="EN-GB" xml:lang="EN-GB"><span><span 
    class="FootnoteReference"><span lang="EN-GB" xml:lang="EN-GB" style="font-size: 10.0pt;">See <i>R v Swain</i> (1992) </span></span></span></span></span></p>
  </body>

# perl -pe 'BEGIN{undef $/;} s/<[pP][ >].*?See <i>(.*?)<\/i>(.*?)<.*?\/[pP]>/<p class="Notes">See <i>$1<\/i>$2<\/p>/gsm;' ff.html
  <body>
    <p class="Notes">See <i>R v Twain</i> (1992) </p>
    <p class="Notes">See <i>R v Swain</i> (1992) </p>
  </body>

说明:

  • BEGIN{undef $/;} =将整个文档视为一个字符串,否则其中包含换行符的html将无法正确处理

  • <[pP[ >] = p-tag的开头(不区分大小写)

  • .*? =很多东西,非贪婪匹配,即http://en.wikipedia.org/wiki/Regular_expression#Lazy_quantification
  • See <i> =字面上寻找那个字符串 - 非常重要,因为这似乎是唯一的共同点
  • (.*?) =将更多内容放入括号组(以后再使用)
  • <\/i> =结束i-tag
  • (.*?) =将更多内容放入括号组(以后再使用)
  • <.*?\/[pP] =结束的p-tag和其他可能的标签在它之前被捣碎(就像你所有的跨度一样)

  • 并将其替换为您想要的字符串,其中$ 1和$ 2是之前在括号中被钩住的内容,即两个(.*?)

  • g =全局搜索 - 每行可能不止一个

  • s =将所有内容视为一行(现在由于BEGIN位于顶部)

答案 1 :(得分:0)

首先使用http://tidy.sourceforge.net将HTML文件转换为正确的XHTML,然后使用xmlstarlet进行必要的XHTML处理。

注意:获取当前版本的xmlstarlet以进行就地XML文件编辑。

这是一个简单但完整的迷你示例:

curl -s http://checkip.dyndns.org > dyndns.html

tidy -wrap 0 -numeric -asxml -utf8 2>/dev/null < dyndns.html > dyndns.xml

# test: print body text to stdout (dyndns.xml)
xml sel -T \
   -N XMLNS="http://www.w3.org/1999/xhtml" \
   -t -m "//XMLNS:body" -v '.' -n \
   dyndns.xml

# edit body text in-place (dyndns.xml)
xml ed -L \
   -N XMLNS="http://www.w3.org/1999/xhtml" \
   -u "//XMLNS:body" -v '<p NEW BODY TEXT </p>' \
   dyndns.xml

# create new HTML file (by overwriting the original one!)
xml unesc < dyndns.xml > dyndns.html

答案 2 :(得分:0)

要整合span标签,您可以使用整洁(2009年3月25日发布的版本)!

# get current tidy version: http://tidy.cvs.sourceforge.net/viewvc/tidy/tidy/
# see also: http://tidy.sourceforge.net/docs/quickref.html#merge-spans

tidy -q -c --merge-spans yes file.html

答案 3 :(得分:-1)

您必须检查输入文件以验证是否可以进行某些假设。根据您的两个例子,我做了以下假设。您需要检查它们并获取一些示例输入文件以验证您是否已找到所有假设。

  • 该文件包含一个<body></body>对中的单个脚注。身体标签总是存在并且形成良好。

  • 脚注隐藏在<p></p>对内的一个地方以及一个或多个<span></span>标记内。 <!...>标记可以被丢弃。

以下Perl脚本适用于您提供的两个示例(在Linux上使用Perl 5.10.0)。 在使用之前,请确保备份原始html文件。默认情况下,它只会在stdout上打印结果而不更改任何文件。

#!/usr/bin/perl

$overwrite = 0;

# get rid of default line separator to facilitate slurping in a $scalar var
$/ = '';
foreach $filename (@ARGV)
{
  # slurp entire file in $text variable
  open FH, "<$filename";
  $full_text = <FH>;
  close FH;

  if ($overwrite)
  {
      ! -f "$filename.bak" && rename $filename, "$filename.bak";
  }

  # match everything that is found before the body tag, everything
  # between and including the body tags, and what follows
  # s modifier causes full_text to be considered a single long string
  # instead of individual lines
  ($before_body, $body, $after_body) = ($full_text =~ m!(.*)<body>(.*)</body>(.*)!s);
  #print $before_body, $body, $after_body;

  # Discard unwanted tags from the body
  $body =~ s%<span.*?>%%sg;
  $body =~ s%</span.*?>%%sg;
  $body =~ s%<p.*?>%%sg;
  $body =~ s%</p.*?>%%sg;
  $body =~ s%<!.*?>%%sg;
  # Remaining leading and trailing whitespace likely to be newlines: remove
  $body =~ s%^\s*%%sg;
  $body =~ s%\s*$%%sg;

  if ($overwrite)
  {
    open FH, ">$filename";
    print FH $before_body, "<body>\n<p class=\"Notes\">$body</p>\n</body>", $after_body;
    close FH;
  }
  else
  {
        print $before_body, "<body>\n<p class=\"Notes\">$body</p>\n</body>", $after_body;
  }
}

使用它:

./script.pl file1.html 
./script.pl file1.html file2.html
./script.pl *.html

调整它,当你开心时设置$ overwrite = 1。该脚本仅在尚不存在的情况下创建.bak。

答案 4 :(得分:-2)

如果每个文件有1个条目,这些文件中没有严格的结构,可能还有多行,我会选择php或perl脚本逐个文件处理它们,同时在模式不匹配时发出合适的警告

使用

php -f thescript.php

执行包含

的脚本.php
<?php
$path = "datapath/";
$dir = opendir($path);
while ( ( $fn = readdir($dir) ) !== false )
{
    if ( preg_match("/html$/",$fn) ) process($path.$fn);
}

function process($file)
{
    $in = file_get_contents($file);
    $in2 = str_replace("\n"," ",strip_tags($in,"<i>"));
    if ( preg_match("#^(.*)<i>(.*)</i>(.*)$#i",$in2,$match) )
    {
         list($dummy,$p0,$p1,$p2) = $match;
         $out = "<body>$p0<i>$p1</i>$p2</body>";
         file_put_contents($file.".out",$out);
    } else {
         print "Problem with $file? (stripped down to: $in2)\n";
         file_put_contents($file.".problematic",$in);
    }
}
?>

你可以根据自己的需要调整它,直到失误次数足够低,可以手动完成最后几次。您可能需要添加一些$p0 = trim($p0);等来清理所有内容。