0

大约有 100 个文件,我需要遍历每个文件并删除它们之间的所有数据,<style>并且</style>+ 删除这些标签。

例如

<html>
<head> <title> Example </title> </head>
<style>
p{color: red;
background-color: #FFFF;
}
div {......
...
}
</style>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>

应该成为

<html>
<head> <title> Example </title> </head>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>

此外,在某些文件中,样式模式就像

<style type="text/css"> blah </style>

或者

<link rel="stylesheet" type="text/css" href="$url_path/gridsorting.css">

我需要删除所有 3 种模式。我如何在 Perl 中做到这一点?

4

6 回答 6

6
use strict;
use warnings;

use XML::LibXML qw( );

my $qfn = 'a.html';

my $doc  = XML::LibXML->load_html( location => $qfn );
my $root = $doc->documentElement();

for my $style_node ($root->findnodes('//style')) {
   $style_node->parentNode()->removeChild($style_node);
}

{
   open(my $fh, '>', $qfn)
      or die;
   print($fh $doc->toStringHTML());
}

它正确处理:

  • 标记中带有属性或空格的样式元素,
  • 跨越多行的样式元素,
  • 跨越多行的样式标签,
  • 包含样式元素的一部分和其他内容的行,
  • 具有多个样式元素的文档,
  • 在属性值中看起来像样式标签的东西,
  • 看起来像 CDATA 块中的样式标签的东西,以及
  • 看起来像评论中的样式标签的东西。

截至本次更新,其他解决方案仅处理其中的 2 或 3 个。

于 2012-10-03T06:03:31.847 回答
4

Ikegami 是对的,你真的应该至少使用一个 HTML/XML 解析器来完成这项任务。我个人喜欢使用Mojo::DOM解析器。这是您的 HTML 的文档对象模型接口,它支持CSS3 选择器,使其在您需要时非常灵活。然而,这对它来说非常简单:

#!/usr/bin/env perl

use strict;
use warnings;

use Mojo::DOM;

my $content = <<'END';
<html>
<head> <title> Example </title> </head>
<style>
p{color: red;
background-color: #FFFF;
}
div {......
...
}
</style>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>
END

my $dom = Mojo::DOM->new( $content );
$dom->find('style')->pluck('remove');

print $dom;

pluck方法有点令人困惑,但它实际上只是对每个结果对象执行方法的简写。类似的线可以是

$dom->find('style')->each(sub{ $_->remove });

这更容易理解但不那么可爱。


在阅读您的编辑后,您必须处理的不仅仅是您的基本表单,我必须进一步强调这就是为什么您使用解析器来修改 HTML 而不是让您的正则表达式增长到荒谬的比例。

现在让我们说$content变量也包含这些行

<link rel="stylesheet" type="text/css" href="$url_path/gridsorting.css">
<link rel="icon" href="somefile.jpg">

您要删除第一个而不是第二个的位置。您可以通过以下两种方式之一执行此操作。

$dom->find('link')->each( sub{ $_->remove if $_->{rel} eq 'stylesheet' } );

此机制使用对象方法(并且 Mojo::DOM 将属性公开为哈希键)来仅删除link具有rel=stylesheet. 但是,您可以仅对find这些元素使用 CSS3 选择器,并且由于 Mojo::DOM 具有完整的 CSS3 选择器支持,您可以这样做

$dom->find('link[rel=stylesheet]')->pluck('remove'); 

CSS3 选择器语句可以用逗号连接以查找与任一选择器匹配的所有标签,因此我们可以简单地包含该行

$dom->find('style, link[rel=stylesheet]')->pluck('remove');

并一举摆脱所有令人反感的样式表!

于 2012-10-03T21:18:11.160 回答
2

另一种可能的解决方案是使用HTML::TreeBuilder.

#!/usr/bin/perl

use strict;
use warnings;
use HTML::TreeBuilder 5; # Ensure weak references in use

foreach my $file_name (@ARGV) {
  my $tree = HTML::TreeBuilder->new; # empty tree
  $tree->parse_file($file_name);
  # print "Hey, here's a dump of the parse tree of $file_name:\n";
  # $tree->dump; # a method we inherit from HTML::Element
  foreach my $e ($tree->look_down(_tag => "style")) {
      $e->delete();
  }
  foreach my $e ($tree->look_down(_tag => "link", rel => "stylesheet")) {
      $e->delete();
  }
  print "And here it is, bizarrely rerendered as HTML:\n",
    $tree->as_HTML, "\n";

  # Now that we're done with it, we must destroy it.
  $tree = $tree->delete; # Not required with weak references
}
于 2012-10-04T04:41:19.513 回答
1

一种使用方式sed

sed '/<style>/,/<\/style>/d' file.txt

结果:

<html>
<head> <title> Example </title> </head>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>
于 2012-10-03T06:07:12.920 回答
0
perl -lne 'print unless(/<style>/.../<\/style>/)' your_file

测试如下:

> cat temp
<html>
<head> <title> Example </title> </head>
<style>
p{color: red;
background-color: #FFFF;
}
div {......
...
}
</style>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>


> perl -lne 'print unless(/<style>/.../<\/style>/)' temp
<html>
<head> <title> Example </title> </head>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>
> 

如果你想就地做,那么:

perl -i -lne 'print unless(/<style>/.../<\/style>/)' your_file
于 2012-10-03T09:53:35.723 回答
0

我想出了一种方法,你可以尝试以下方法:

#! /usr/bin/perl -w
use strict;
my $line = << 'END';
<html>
<head> <title> Example </title> </head>
<style>
p{color: red;
background-color: #FFFF;
}
div {......
...
}
</style>
<body>
<p> hi I'm a paragraph. </p>
</body>
</html>
END

$line =~ s{<style[^>]*.*?</style>.}{}gs;
print $line;
于 2012-10-06T01:34:37.367 回答