2014-02-18 2 views
-1

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

+2

'/ \ <(\ /? [A-Za-Z0-9] *) (. *?) \> /' Не прав. Причина использования существующего инструмента заключается не в том, что регулярное выражение плохое, это потому, что гораздо сложнее написать собственный синтаксический анализатор, чем использовать существующий (с использованием регулярного выражения или иначе). – ikegami

+0

образец того, где он может терпеть неудачу на xhtml? Я просматриваю список тэгов html, и это должно работать над действительным html ... это, конечно, слишком разрешительно. –

+0

Я явно не утверждал, что противоречил вашей претензии, что проще написать собственный парсер, чем изучать существующий. – ikegami

ответ

0

Решение, которое я разместил, наивно.

Plus:

  • на случайных страницах, кажется, обрабатывать около 9 из 10 XHTML веб-страниц в Интернете. он может обрабатывать обычные файлы xhtml стека, но может работать с более необычными функциями (такими как DTD и т. д.). если другая программа сгенерировала ваш вывод xhtml, она может работать все время.

  • кривые обучений здесь составляет около 1/10 по сравнению с реального DOM разбором

  • код здесь составляет около 1/10 размера по сравнению с реальным DOM разбора.

  • знакомое знание relx perl можно использовать.

  • будьте готовы, чтобы этот инструмент был ограничен. если вы перерастите свои возможности, вам, возможно, придется изучить лучший парсер DOM.

Минус:

  • он совершенно непригоден, если требуется идеальное DOM синтаксический. этот код прерывается. это следует за беркелями, а не по методу &.

  • но совершенные анализаторы DOM также могут работать с плохими HTML-документами.

  • , и если вы уже знаете разбор DOM, то для этого нужно немного времени. используйте Mojolicious или XML :: LibXML. вы можете также придерживаться лучшего решения тогда.

, давая этому коду рефлексивный -1 голос, игнорирует его использование. иногда обычная отвертка может выполнять работу, где лучше будет филипсов. этот код является обычной отверткой для винта Philips. stackoverflow - это сайт, к которому новички также нуждаются в быстрых решениях; не только эксперты. вот почему я опубликовал его для начала.

Исправления исправлений исправлены, хотя цель здесь явно не иметь дело со всеми возможными действительными и недействительными, нормальными и безумными, правильными и неправильными перестановками xml и xhtml.

/IAW