如何删除Perl中的每个第三个HTML标记?

时间:2009-03-16 01:11:37

标签: html regex perl

这是一个快速编写的脚本,但由于不熟悉正则表达式和Perl,我遇到了一些困难。

该脚本应该在HTML文件中读取。文件中有一个位置(单独),我有一堆< div> s。我想删除它们中的每一个 - 它们分为四个部分。

我的下面的脚本无法编译,更不用说了。

#!/usr/bin/perl
use warnings;
use strict;


&remove();

sub remove {
    my $input = $ARGV[0];
    my $output = $ARGV[1];
    open INPUT, $input or die "couldn't open file $input: $!\n";
    open OUTPUT, ">$output" or die "couldn't open file $output: $!\n";

    my @file = <INPUT>;
    foreach (@file) {
        my $int = 0;
        if ($_ =~ '<div class="cell">') {
        $int++;
        { // this brace was the wrong way
        if ($int % 4 == 3) {
        $_ =~ '/s\<div class="cell">\+.*<\/div>/;/g';
            }
    }
    print OUTPUT @file;
}

感谢您的帮助。我知道用正则表达式解析是错误的,但我只想让这个工作。

事后:问题几乎已经解决了。而且我很惭愧那些告诉我正则表达不好的人 - 我知道这一点开头。但话说回来,我想要快速的东西,并编写了产生它的XSLT。在这种情况下,我没有再次运行它的源代码,否则我会将它编程到XSLT中。

5 个答案:

答案 0 :(得分:4)

我同意HTML不能真正被正则表达式解析,但是对于你知道格式的HTML的快速小黑客,正则表达式工作得很好。用正则表达式重复替换的技巧是将重复放入正则表达式。如果你不这样做,你就会遇到将正则表达式匹配器的位置与你正在阅读的输入同步的麻烦。

这是我写Perl的快速而肮脏的方式。即使它嵌套在前两个div中,它也会删除第三个div元素。读取整个文件,然后使用“g”全局替换修饰符使正则表达式进行计数。如果您之前没有看过“x”修饰符,那么它可以让您为格式添加空格 - 在正则表达式中忽略空格。

remove(@ARGV);

sub remove {
  my ($input, $output) = @_;

  open(INPUT, "<", $input) or die "couldn't open file $input: $!\n";
  open(OUTPUT, ">", $output) or die "couldn't open file $output: $!\n";

  my $content = join("", <INPUT>);
  close(INPUT);

  $content =~ s|(.*? <div \s+ class="cell"> .*? <div \s+ class="cell"> .*?)
                <div \s+ class="cell"> .*? </div>
                (.*? <div \s+ class="cell">)|$1$2|sxg;

  print OUTPUT $content;
  close OUTPUT;
}

答案 1 :(得分:3)

当您的代码无法编译时,请阅读您收到的错误和警告消息。 如果它们没有意义,请咨询perldoc perldiag(或 把“使用诊断”;在你的代码中为你自动执行此操作)。

答案 2 :(得分:2)

嗯,你不应该用正则表达式解析HTML。既然如此,它可能不会“正常工作”。

理想情况下,您需要使用HTML解析和操作库。不要将HTML视为一个用字符串操作的大字符串:它是一个序列化的,格式化的数据结构。为了这个目的,您应该使用库 。各种库已经修复了你可能面临的数百个错误,使得针对它们编写的简单HTML操作例程“正常工作”的可能性要高出数十亿倍。主级别的Perl程序员通常不会以这种方式解析HTML,并不是因为他们对代码质量和纯度非常痴迷和不合理 - 这是因为他们知道重新发明轮子本身不太可能产生像滚动一样平滑的东西。现有的机器。

我推荐HTML :: Tree,因为它的功能与我对HTML(和XML)的看法相同。我认为还有一些其他库可能更受欢迎。

真正的事实是,如果你甚至无法让你的程序编译,你需要花更多的时间(半天左右)来计算出基础知识,然后再来看看求助。您在使用s /// g正则表达式替换运算符的语法中有错误,并且在进一步操作之前需要了解它应该如何工作。这并不难,你可以从Camel书,perlretut联机帮助页或其他几个来源找到你需要的东西。如果您现在还没有学习如何调试程序,那么您在此处获得的任何帮助都可能会带您进入下一个语法错误,而这个错误是您无法通过的。

答案 3 :(得分:2)

一旦你得到了相互匹配的波浪形括号,并开始正确使用替换正则表达式,你还需要移动

my $int = 0;

out for for循环 - 当前正在读取的每一行上重置它,因此它只有0或1的值。

答案 4 :(得分:1)

子程序已经迷失了方向。首先来看看它的结构:

sub remove {                                   # First opening bracket
    my $input = $ARGV[0];
    my $output = $ARGV[1];
    open INPUT, $input or die "couldn't open file $input: $!\n";
    open OUTPUT, ">$output" or die "couldn't open file $output: $!\n";

    my @file = <INPUT>;
    foreach (@file) {                          # Second opening bracket
        my $int = 0;
        if ($_ =~ '<div class="cell">') {      # Third opening bracket
        $int++;
        {                                      # Fourth opening bracket
        if ($int % 4 == 3) {                   # Fifth opening bracket
        $_ =~ '/s\<div class="cell">\+.*<\/div>/;/g';
            }                                  # First closing bracket
    }                                          # Second closing bracket
    print OUTPUT @file;
}                                              # Third closing bracket
                                               # No fourth closing bracket?
                                               # No fifth closing bracket?

我想你想要这个:

sub remove {
    my $input = $ARGV[0];
    my $output = $ARGV[1];
    open INPUT, $input or die "couldn't open file $input: $!\n";
    open OUTPUT, ">$output" or die "couldn't open file $output: $!\n";

    my @file = <INPUT>;
    foreach (@file) {
        my $int = 0;
        if ($_ =~ '<div class="cell">') {
          $int++;
        }
        if ($int % 4 == 3) {
          $_ =~ '/s\<div class="cell">\+.*<\/div>/;/g';
        }
    }
    print OUTPUT @file;
}

那将编译,并将我们带到下一个问题:你为什么单引号正则表达式? (另见Cebjyre关于my $int = 0的位置的观点。)

(要了解Ysth的观点,您还可以使用perl -Mdiagnostics script-name运行脚本以获取更长的诊断消息。)