如何触发Perl多行替换

时间:2013-05-03 11:20:03

标签: perl doctype multiline

我有一个HTML文件的文件夹,其中包含我需要删除的DOCTYPE声明,因此一个不太好的解析器可以成功地将其作为XML加载。

我一直在尝试使用perl进行替换,但是当我运行替换时没有进行任何更改,我无法弄清楚原因。任何人都可以识别我需要做出的正确标志或规范,以便在此删除DOCTYPE处理指令。

这是我想要操作的示例文件。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
  <meta name="generator" content=
  "HTML Tidy for Linux/x86 (vers 25 March 2009), see www.w3.org" />
  <title></title>
</head>
  <body>
  </body>
</html>

这是我正在尝试使用的perl单线程,用于查找尖括号,感叹号以及近角括号之前的所有内容。它包含perl替换标志,其他帖子建议应该用于多行匹配 - m用于多行,s用于允许新行与正则表达式匹配。然后我用空字符串替换匹配。

perl -i -e 's/<![^>]+>//gsm' `find . -name '*.html'`

我无法弄清楚原因,但运行此命令后,DOCTYPE不会从文件中删除。有谁知道为什么?

2 个答案:

答案 0 :(得分:1)

首先,您似乎缺少-p参数,用于逐行处理输入。如果没有-i-p似乎没那么多。

其次,由于-pi逐行处理输入,因此它无法替换跨越多行的正则表达式。

您可以编写Perl脚本。此脚本应该在命令行上传递的所有文件的整个内容上运行正则表达式:

use IO::All;

foreach my $file (@ARGV) {
    my $content = io($file)->slurp;
    $content =~ s/<![^>]+>//g;
    $content > io($file);
}

命令cpan IO:All应安装IO:All模块(如果您的系统中没有)。

P.S。 ms选项仅影响.^$。我想你可以省略它们。

答案 1 :(得分:1)

您需要的是-0777开关,它将整个文件读入一个字符串。如果不使用,则会以逐行模式读取文件,并且永远不能以这种方式匹配多行语句。

另外,正如Andomar指出的那样,你错过了-p开关,但我认为你已经明白了。

除了/g修饰符之外,正则表达式中的修饰符在这种情况下无关紧要。 /m仅影响^$/s会导致通配符.也匹配换行符。这些都不适用于你的正则表达式。

所以基本上,你需要类似的东西:

perl -0777 -pi -e 's/<![^>]+>//g' ...

旁注:

理想情况下,应该使用解析器处理Html,因此我花了几分钟时间使用HTML::Parser,它有一个方便的选项,可以通过添加处理程序来删除声明。这样的东西似乎打印好单个文件:

perl -MHTML::Parser -we '
    $p = HTML::Parser->new(default_h => [sub {print @_},'text'] ); 
    $p->handler(declaration => ''); 
    $p->parse_file(shift) or die $!; " yourfile.html

我认为这会有点过分,所以我放弃了尝试使用-pi就地编辑开关修复它,但它(可能)很容易在脚本中实现。