代码之家  ›  专栏  ›  技术社区  ›  Dr. Frankenstein

如何用perl-one行程序删除HTML SPAN标记?

  •  -1
  • Dr. Frankenstein  · 技术社区  · 16 年前

    我想在使用Perl的终端中作为一个单行程序执行以下VIM替换。我更愿意考虑出现任何空白或换行,而不是像我下面这样明确地为它们提供服务。

    %s/blockDontForget">\n*\s*<p><span><a\(.*\)<\/span>/blockDontForget"><p><a\1/g 
    

    我试过了:

    perl -pi -e 's/blockDontForget"><p><span><a(.*)<\/span>/blockDontForget"><p><a$1/msg'
    

    我想我误解了国旗。我哪里出错了?谢谢。

    编辑:

    上面的示例是从以下HTML中去掉跨距:

    <div class="block blockDontForget">
        <p><span><a href="../../../foo/bar/x/x.html">Lorem Ipsum</a></span></p>      
    

    编辑:

    这只是 <span> S和 </span> 是中间的吗? <p> <a> 来自“blockdontforget”类
    </div> 我想删除的(有很多或这些 blockDontForget 在我要保留的锚定内使用跨度进行划分)。

    3 回复  |  直到 16 年前
        1
  •  1
  •   Community Mohan Dere    9 年前

    而不是将自己限制在一个行程序和正则表达式中,这实际上是该工作的错误工具(请参见 RegEx match open tags except XHTML self-contained tags ,使用树分析器。这是你的任务 HTML::TreeBuilder :

    #!perl
    use strict;
    use warnings;
    
    use HTML::TreeBuilder;
    
    my $html  = HTML::TreeBuilder->new;
    my $root  = $html->parse_file( *DATA ); # or <>
    
    foreach my $div ( $root->look_down( '_tag', 'div' ) ) {
        next unless class_selector( $div, 'blockDontForget' );
        foreach my $p ( $div->look_down( '_tag', 'p' ) ) {
            foreach my $span ( $p->look_down( '_tag', 'span' ) ) {
                my $a = $span->look_down( '_tag', 'a' );
                $span->replace_with( $a );
                }
            }
        };
    
    print $root->as_HTML;
    
    sub class_selector
        {
        my( $elem, $class ) = @_;
    
        scalar
        grep { /\A$class\z/ } 
        split /\s+/, 
        $elem->attr( 'class' );
        }
    
    __END__
    
    <div class="block">
        <p><span><a href="../../../foo/bar/x/x.html">Stay spanned</a></span></p> 
    </div>
    
    <p><span><a href="../../../foo/bar/x/x.html">Spanned</a></span></p> 
    
    <div class="block blockDontForget">
        <p><span><a href="../../../foo/bar/x/x.html">No span</a></span></p>      
    </div>
    

    写这篇文章的方法比较短(不搞混或打高尔夫球),还有很多概括它的方法,但这可能是最容易阅读的,足以让你开始一个正确的解决方案。把这个保存在一个文件中,你就有了一个行程序。这取决于您修复这些位来处理参数列表,漂亮地打印HTML,并保存结果。

        2
  •  -1
  •   Axeman maxelost    16 年前

    一段时间以来,我一直在寻找一种自我“分区替换”的方法。这是我最近想到的:

    use English qw<@LAST_MATCH_START @LAST_MATCH_END>;
    
    #...
    
    $snippet =~ m|\Q<div class="block blockDontForget">\E(.*?)</div>|msx 
    and substr( $snippet
              , $LAST_MATCH_START[1]
              , $LAST_MATCH_END[1] - $LAST_MATCH_START[1]
          )
          =~ s|(?i:\s*</?span\b[^>]*>\s*)||msg
          ;
    

    更紧凑的版本是:

         m|\Q<div class="block blockDontForget">\E(.*?)</div>|msx 
    and substr( $_, $-[1], $+[1] - $-[1] ) =~ s|\s*</?span\b[^>]*>\s*||gimsx
    ;
    
        3
  •  -1
  •   Zaid    16 年前

    根据您的原始代码段:

    perl -0777 -pi -e 's{blockDontForget">.*?<p>.*?<span>.*?<a(.*?)>.*?</span>}{blockDontForget"><p><a$1}sg' fileName
    
    • 这个 -0777 命令开关将整个文件拖进,而不是一行一行地处理它。
    • 不需要 m 本例中的修饰语。
    • 这个 s 修饰符与换行符匹配( \n . 同时,它允许您使用 .*? 匹配中间换行符和空格0次或更多次,但尽可能少。

    如果你需要剥光所有的 <span> S和 </span> 出了,那么有一种更简单的方法可以做到:

    perl -pi -e 's#</?span>##g' fileName
    

    如果只是 <SPAN & GT; S和 </SPAN & GT; 来自S "block blockDontForget" 班级:

    perl -0777 -pi -e 's{(blockDontForget">.*?<p>).*?<span>(.*?)</span>.*?(</div>)}{$1$2$3}sg' fileName