Thread Platzhalter für HTML-Ausdrücke (reguläre Ausdrücke) (47 answers)
Opened by vitopetre at 2010-04-02 09:42

topeg
 2010-04-06 15:24
#135775 #135775
User since
2006-07-10
2611 Artikel
BenutzerIn

user image
ich habe mal aus Neugier einen kleinen Parser geschrieben. Er ist weder Perfekt noch mit anderen Modulen zu vergleichen! Es ist nur eine Machbarkeitsstudie. Es ist nicht für den normalen Gebrauch geeignet.
Also nach all den Warnungen:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use LWP::Simple;

my $file=shift;

my $data='';

if($file=~m!^http://!)
{ $data=get($file); }
elsif(-f $file)
{ $data=eval{local($/,@ARGV)=(undef,$file); <>}; }
elsif($file eq '-')
{
  local $/=undef;
  $data=<STDIN>;
}
else
{ $data=$file; }

print Dumper(parse($data));

########################################################################

sub parse
{
  # Liste mit allen Single-Tags
  my @single=qw( br hr );
  # Abschuss-Tag erzwingen
  my %optional=( li=>[qw(ul ol)] td=>[qw(tr th)]);

  my $data=shift || '';
  my $tree={name=>'root',childs=>[],opts=>{}};

  my @deep=({name=>'root',ref=>$tree});

  #Sind überhaupt html-tags enthalten?
  return undef if($data!~m!</?[\w\-_]+\s*(?:[\w\-_]+\s*=\s*(?:"[^"]*"|'[^']*'|[^<>]*)\s*)*\s*?/?>!s);

  # alle Tags finden und bearbeiten
  while($data=~m#<(/?[A-Za-z0-9][\w\-_]+)\s*((?:[\w\-_]+\s*=\s*(?:"[^"]*"|'[^']*'|[^<>]*)\s*)*)\s*?(/?)>((?:<!--.*?-->|[^<>]*)*)#gcs)
  {
    my $name=lc($1);
    my $opts=$2;
    my $single=$3;
    my $text=$4;
    my $end=0;

    # Single-Tag erzwingen
    $single=1 if(grep{lc($_) eq lc($name)}@single);

    $text=~s/^\s*(.*?)\s*$/$1/gs;

    # es handelt sich um einen Abschluss-Tag
    if(substr($name,0,1) eq '/')
    {
      # / entfernen
      substr($name,0,1,'');
      # Schon letzter end-tag
      last unless(@deep>1);
      # Passenden Abschluss-Tag finden
      while(my $p=shift(@deep))
      { last if($p->{name} eq $name); }
      # keinen passenden gefunden
      last unless(@deep);
      # Block als Singeltag verarbeiten
      $single=1;
      $end=1;
    }

    # Abschusstag erzwingen
    if(exists($optional{$name}) && @deep>0)
    {
      my $cnt=1;
      while($cnt<@deep)
      {
        last if(grep{$deep[-$cnt]->{name} eq $_}@{$optional{$name}});
        $cnt++;
      }
      $end=-$cnt;
    }

    # es ist kein Abschluss-Tag
    if($end<1)
    {
      # neuen Eintrag Erzeugen
      my $ref={name=>$name,childs=>[],opts=>{}};
      push(@{$deep[$end]->{ref}->{childs}},$ref);

      # wir haben keine Single-Tag
      unshift(@deep,{name=>$name,ref=>$ref}) if(!$single);

      # Optionen Parsen
      if($opts)
      {
        while($opts=~s!(\w+)\s*=\s*"([^"]*)"!!s)
        { $ref->{opts}->{$1}=$2; }
        while($opts=~s!(\w+)\s*=\s*'([^']*)'!!s)
        { $ref->{opts}->{$1}=$2; }
        while($opts=~s!(\w+)\s*=\s*(\S*)!!s)
        { $ref->{opts}->{$1}=$2; }
      }
    }

    push(@{$deep[0]->{ref}->{childs}}, $text) if($text);
  }

  return $tree;
}

XHTML wird ohne Probleme geparst. Bei HTML fehlen viele Ausnahmeegelungen

Edit:
Ist mir gerade aufgefallen, dass der RegExp nicht mit HTML-Kommentaren klar kommt. Habe ich eben ergänzt.
Last edited: 2010-04-06 16:38:37 +0200 (CEST)

View full thread Platzhalter für HTML-Ausdrücke (reguläre Ausdrücke)