Как я могу удалить теги HTML span с помощью Perl one liner? - PullRequest
0 голосов
/ 26 мая 2010

Я хочу выполнить следующую замену vim как однострочную в терминале с Perl. Я предпочел бы учесть любые случаи появления пробелов или новых строк, а не явно обслуживать их, как я ниже.

%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'

Полагаю, я неправильно понимаю флаги. Куда я иду не так? Спасибо.

EDIT:

Приведенный выше пример убирает интервалы из следующего html:

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

EDIT:

Это просто <span> и </span>, которые находятся между <p> и <a> из класса "blockDontForget"
</div>, которые я хочу удалить (есть много или эти blockDontForget делений с интервалами внутри якорей, которые я хочу сохранить).

Ответы [ 3 ]

1 голос
/ 27 мая 2010

Вместо того, чтобы ограничивать себя однострочниками и регулярными выражениями, которые на самом деле являются неподходящими инструментами для этой работы (см. RegEx соответствует открытым тегам, за исключением автономных тегов XHTML ), используйте анализатор дерева. Вот ваша задача с 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 и сохранения результата.

0 голосов
/ 26 мая 2010

Я некоторое время искал способ сделать «зонную замену» сам.Это самое близкое, что я придумал:

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
;
0 голосов
/ 26 мая 2010

Согласно вашему оригинальному фрагменту:

perl -0777 -pi -e 's{blockDontForget">.*?<p>.*?<span>.*?<a(.*?)>.*?</span>}{blockDontForget"><p><a$1}sg' fileName
  • Командный ключ -0777 пропускает весь файл, а не обрабатывает его построчно.
  • В этом случае модификатор m не требуется.
  • Модификатор s сопоставляет символы новой строки (\n) и ., что позволяет использовать .*? для сопоставления промежуточных строк новой строки и пробелов 0 или более раз, но как можно меньше раз. *

Если вам нужно убрать все <span> с и </span> с, то есть гораздо более простой способ сделать это:

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

А если это просто <span> с и </span> с из "block blockDontForget" класса:

perl -0777 -pi -e 's{(blockDontForget">.*?<p>).*?<span>(.*?)</span>.*?(</div>)}{$1$2$3}sg' fileName
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...