Wie kann ich mehrere Wörter ersetzen, die jeweils an einem anderen Wort gehasht, in einem HTML-Attribut mit Perl regex?

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

  •  07-07-2019
  •  | 
  •  

Frage

Ich schreibe ein HTML obfuscator, und ich habe eine Hash-Korrelieren benutzerfreundlichen Namen (von IDs und Klassen) zu verschleierte Namen (wie a, b, c, etc.). Ich habe Probleme mit einem regulären Ausdruck kommen zum Erreichen ersetzt so etwas wie

<div class="left tall">

mit

<div class="a b">

Wenn Etiketten mit nur einer Klasse annehmen könnte, würde die regexp einfach so etwas wie

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

Wie soll ich dies korrigieren für in Anführungszeichen für mehrere Klassennamen zu berücksichtigen? Vorzugsweise sollte die Lösung sein Perl kompatibel.

War es hilfreich?

Lösung

Ich glaube, ich würde dies tun:

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

Andere Tipps

Sie sollten nicht in erster Linie mit einem regulären Ausdruck dafür sein. Sie versuchen, zu viel mit einer Regex zu tun (siehe Können Sie einige Beispiele dafür, warum es schwierig ist, XML und HTML mit einer Regex zu analysieren? , warum). Was Sie brauchen, ist ein HTML-Parser. Siehe Können Sie ein Beispiel für das Parsen HTML mit Ihrem Lieblings-Parser? Beispiele unter Verwendung einer Vielzahl von Parsern.

Hier finden Sie aktuelle HTML::Parser . Hier ist eine, wahrscheinlich unvollständig, Umsetzung:

#!/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>
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top