Я знаю, что это похоже на пламенную приманку, но это не так. выслушай меня. потому что stackexchange предпочитает вопросы (и это в первую очередь ответ), позвольте мне спросить «что случилось со следующим?».Regex Parsing для XML или XHTML DOM в Perl
Regex's re не подходит для разбора DOM. Тем не менее, когда они пригодны для использования, у них есть красивая обобщаемость, простота использования и отсутствие дополнительной кривой обучения по сравнению с комплексными парсерами DOM.
так, я думал, что поделюсь хаком, который делает регулярное выражение подходящим для быстрых и грязных изменений DOM. он добавляет временные метки gid в html и их закрывающие атрибуты, а затем использует обратные ссылки regex.
Код милостиво короткий, и соответствует одной из философий perl, что некоторые решения могут быть лучше, если они короче в времени программирования, чем во время выполнения.
#!/usr/bin/perl -w
use strict;
use warnings FATAL => qw{ uninitialized };
################################################################
sub tokenize {
my $GLOBAL; (defined($_[0])) and do { $GLOBAL = $_; $_ = $_[0]; };
my @xmlstack;
my $gid=0;
my $addgid= sub {
my ($s,$e) = @_;
($e =~ /\/$/) and return "<$s$e/>"; ## could add gid here, too.
if ($s =~ /^\/(.*)/) {
my $off= pop(@xmlstack);
($off->[0] eq $1) or die "not a valid document at id=$gid. (wanted = $off->[0] . had = $s).\n";
return "<$s gid=\"".($off->[1])."\">"; ## not legal html now, but easy to remove
} else {
push(@xmlstack, [$s, ++$gid]);
return "<$s gid=\"$gid\">";
}
};
my $U="#!#";
(/$U/) and die "sorry, this is a hack. pick any other unique string than '$U'\n";
s/<!--(.*?)-->/$U$1$U/gms; # comments can contain html tags
s/\<(\/?[a-zA-Z0-9]*)(.*?)\>/$addgid->($1,$2)/emsg;
s/$U(.*?)$U/<!--$1-->/gms;
(@xmlstack) and die "unfinished business: ".pop(@xmlstack)->[0]."\n";
if ($GLOBAL) { my $CHANGED= $_; $_ = $GLOBAL; return $CHANGED; } else { return $_; }
}
sub untokenize {
my $GLOBAL; (defined($_[0])) and do { $GLOBAL = $_; $_ = $_[0]; };
s/ gid="[0-9]+">/>/g; ## buglet: could mistakenly remove gid from inside comments.
if ($GLOBAL) { my $CHANGED= $_; $_ = $GLOBAL; return $CHANGED; } else { return $_; }
}
################################################################
$_ = "<html>\n<body>\n
<p> <sup>a</sup><sub>b</sub>. </p>.
<hr />
<p> hi<sup>u<sub>ud<sup>udu</sup></sub></sup> </p>.
</body>
</html>
";
tokenize();
## now we can use regex using backreferences
while (/<sup (gid="[0-9]+")>(.*)<\/sup \g1>/gms) {
print "Example matching of all sup's: $1 $2\n"; ## could call recursively
}
## another example: add a class to sup that is immediately followed by a sub
s/\<sup (gid="[0-9]+")\>(.*)<\/sup \g1>\s*\<sub/<sup class="followed" $1>$2<\/sup $1><sup/gms;
print untokenize($_);
это, вероятно, до сих пор знает Уйму HTML осложнений, но он может обрабатывать много Xhtml и XML DOM рабочих мест в противном случае не подходит для регулярных выражений разбора.
'/ \ <(\ /? [A-Za-Z0-9] *) (. *?) \> /' Не прав. Причина использования существующего инструмента заключается не в том, что регулярное выражение плохое, это потому, что гораздо сложнее написать собственный синтаксический анализатор, чем использовать существующий (с использованием регулярного выражения или иначе). – ikegami
образец того, где он может терпеть неудачу на xhtml? Я просматриваю список тэгов html, и это должно работать над действительным html ... это, конечно, слишком разрешительно. –
Я явно не утверждал, что противоречил вашей претензии, что проще написать собственный парсер, чем изучать существующий. – ikegami