Как заменить несколько слов, каждое из которых хэшировано на альтернативное слово, в атрибуте HTML с помощью регулярного выражения Perl?

StackOverflow https://stackoverflow.com/questions/1217068

  •  07-07-2019
  •  | 
  •  

Вопрос

Я пишу обфускатор HTML, и у меня есть хэш, сопоставляющий удобные для пользователя имена (идентификаторов и классов) с запутанными именами (например, a, b, c и т. д.).У меня возникли проблемы с созданием регулярного выражения для замены чего-то вроде

<div class="left tall">

с

<div class="a b">

Если бы теги могли принимать только один класс, регулярное выражение выглядело бы примерно так:

s/(class|id)="(.*?)"/$1="$hash{$2}"/

Как мне исправить это, чтобы учесть несколько имен классов в кавычках?Предпочтительно решение должно быть Perl-совместимым.

Это было полезно?

Решение

Думаю, я бы сделал это:

s/  
    (class|id)="([^"]+)"
/   
    $1 . '="' . (
        join ' ', map { $hash{$_} } split m!\s+!, $2
    ) . '"'
/ex;

Другие советы

Во-первых, вам не следует использовать для этого регулярное выражение.Вы пытаетесь сделать слишком много с помощью одного регулярного выражения (см. Можете ли вы привести несколько примеров того, почему сложно анализировать XML и HTML с помощью регулярных выражений? почему).Что вам нужно, так это парсер HTML.Видеть Можете ли вы привести пример анализа HTML вашим любимым парсером? для примеров с использованием различных парсеров.

Взгляни на HTML::Parser.Вот, возможно, неполная реализация:

#!/usr/bin/perl

use strict;
use warnings;

use HTML::Parser;

{
    my %map = (
        foo => "f",
        bar => "b",
    );

    sub start {
        my ($tag, $attr) = @_;
        my $attr_string = '';
        for my $key (keys %$attr) {
            if ($key eq 'class') {
                my @classes = split " ", $attr->{$key};
                #FIXME: this should be using //, but
                #it is only availble starting in 5.10
                #so I am using || which will do the
                #wrong thing if the class is 0, so
                #don't use a class of 0 in %map , m'kay
                $attr->{$key} = join " ", 
                    map { $map{$_} || $_ } @classes;
            }
            $attr_string .= qq/ $key="$attr->{$key}"/;
        }

        print "<$tag$attr_string>";
    }
}

sub text {
    print shift;
}

sub end {
    my $tag = shift;
    print "</$tag>";
}

my $p = HTML::Parser->new(
    start_h => [ \&start, "tagname,attr" ],
    text_h  => [ \&text, "dtext" ],
    end_h   => [ \&end, "tagname" ],
);

$p->parse_file(\*DATA);

__DATA__
<html>
    <head>
        <title>foo</title>
    </head>
    <body>
        <span class="foo">Foo!</span> <span class="bar">Bar!</span>
        <span class="foo bar">Foo Bar!</span>
        This should not be touched: class="foo"
    </body>
</html>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top