Gå til innhold

Prisguide på HW, hvordan?


Anbefalte innlegg

eksemplene står der, men kan gjenta:

 

*) nøstede tags med manglende close tag:

<div><b>det<i>te</b> er en <b>salig</i> su<b>pp</b></b>e<b>av forskjellige tags</div> dette er <i>ikke</i> bold.

 

*) en noe rotete tag:

kan du finne < taggen her?<input name='utsagn' value="hva skjera' baghera > hepp" size='12'> og ikke noe annet> hva med denne: <input name=uttrykk value="1 < 2">?

Lenke til kommentar
Videoannonse
Annonse

Den første løser jeg ved hjelp av preg_replace_callback. "Svakheten" til regex-funksjonene i dette tilfellet, er at de vil lese forbi de andre HTML-taggene som ligger mellom start- og slutt-taggen for den taggen man leser av. Ved å bruke preg_replace_callback og en while-loop, går jeg gjennom scriptet, fjerner html-taggene jeg har lest og leser på nytt til det ikke er flere HTML-tagger igjen.

 

Regex jeg vil bruke i dette tilfellet må være noe slik som

#<([a-z0-9]+) ?(.*?)?>(.*?)(</\1>|$)#is

 

I funksjonen legger jeg alt inn i en array med passende beskrivelse. Funksjonen retunerer ingenting om det ikke finnes HTML (og derfor ikke noen nøstede tags) i mellom start- og slutt-taggen. Hvis ikke retunerer den koden med start- og slutt-taggen strippet vekk. Loopen fortsetter til alle taggene er strippet vekk. Om ønskelig kan jeg lime inn et fungerende eksempel for dette.

 

Når det gjelder rotete tagger har jeg laget en regex som henter innholdet til HTML-taggene som ikke blir påvirket av < og > mellom " og '.

 

Regex: <([a-z0-9]+)((.*?("|').*?\4 *)*?)>

 

For å lese av attributtene er det bare å kjøre gjennom arrayen man får ved å bruke preg_match_all og dele de inn i arrays osv.

 

Tar forbehold om små feil i regulæruttrykkene.

 

Edit: ser forresten vi har kjørt denne tråden ganske off-topic :whistle:

Endret av RipZ-
Lenke til kommentar
Paste gjerne eksempelkode som løser det ja.

 

Hvis du ikke kan se forbi nøstede tags så kan du vel ikke parse det rett heller?

Du missforstår tydeligvis det jeg skrev. Regulæruttrykket jeg skrev ser forbi nøstede tags. Men det gjør at disse taggene ikke blir parset første gang vi går gjennom koden med uttrykket. Derfor må vi gå gjennom koden flere ganger. Prøvde å forklare dette, men ble kanskje ikke forklart godt nok.

 

$subject = 'nøstede tags, <b> <font size="12">det<i>te</b> er en <b></font>salig</i><a href="oi.denne.er.visst.ikke.lukket.html"> su<b>pp</b>e</b>';

function htmlparse($var) {

global $BODY;

$BODY[ $var[1] ][] = array('html' => strip_tags( $var[3] ), 'atr' => $var[2]);

return (strip_tags($var['3']) != $var['3']) ? $var['3'] : '';

}


while($subject = preg_replace_callback('#<([a-z0-9]+) ?(.*?)?>(.*?)(</\1>|$)#is',"htmlparse",$subject)) {

if($old_subject == $subject)
 break;
else
 $old_subject = $subject;
 
}

print_r( $BODY );

 

Koden over inneholder sikkert en god posjon bugs, men viser at det fungerer å parse nøstede tagger. Har også lagt til en åpen a-tag som ikke blir avsluttet for å vise at den også tar med denne. For å optimalisere koden enda litt mer kunne jeg f.eks bestemt at åpne tagger som befinner seg i bestemte elementer slikt som div, td osv hadde blitt lukket ved enden av disse. Men har ikke tatt meg tid til å gjøre noe slik i eksempelet mitt.

 

Regulæruttrykk blir ofte sett på som trege løsninger og blir ofte undervurdert. Selv bruker jeg det i mange sammenhenger, og bruker det f.eks mye på www.nuffe.net hvor jeg både har en nyhetsagent og en gjesteboktjeneste som benytter det til forskjellige ting (blant annet til å hente bilder osv til nyhetene og hente gamle gjestebokinnlegg fra alxnet-gjesteboker m.m). Selve parsingen av HTML-koden tar sjeldent mer enn en brøkdel av den tiden scriptet bruker på å hente innholdet, så for meg fungerer det utmerket.

 

Edit: Når jeg først er i gang; koden over retunerer følgende array:

 

Array
(
   [b] => Array
       (
           [0] => Array
               (
                   [html] =>  dette
                   [atr] => 
               )

           [1] => Array
               (
                   [html] => salig supp
                   [atr] => 
               )

           [2] => Array
               (
                   [html] => ppe
                   [atr] => 
               )

       )

   [font] => Array
       (
           [0] => Array
               (
                   [html] => dette er en 
                   [atr] => size="12"
               )

       )

   [a] => Array
       (
           [0] => Array
               (
                   [html] =>  suppe
                   [atr] => href="oi.denne.er.visst.ikke.lukket.html"
               )

       )

   [i] => Array
       (
           [0] => Array
               (
                   [html] => te er en salig
                   [atr] => 
               )

       )

)

 

Arrayen kan selvfølgelig formes slik som man vil i funksjonen.

Endret av RipZ-
Lenke til kommentar
ok. vil den regexen ta tag som har > inni en av atributtene? eller vil den kunne se at <dette ikke er ment som en htmltag men brukt som tegnet "<"

 

EDIT: Har nå sett resultatet av parsingen. Stemmer det at du mister rekkefølgen/orden på tagene?

Regexen har ikke problemer med "lovlige" < og > (som jeg egentlig ikke vet om er lovlig, men vi sier det i dette eksempelet da).

 

Ja, det stemmer at den mister rekkefølgen i dokumentet. Det kan likevel fikses ved å først gå gjennom koden og nummerere taggene. Grunnen til at vi mister orden er som nevnt tidligere, at man er nødt til å parse koden flere ganger. Man kan selvfølgelig skrive et helt annet regulæruttrykk og fikse dette på en helt annen måte. Men personlig synes jeg at nummerering av taggene blir det enkleste.

 

Vi må heller ikke glemme at koden jeg postet er relativt liten. I en skikkelig HTML-parser er det man ting man må ta hensyn til. F.eks hvilke taggere som bør ha avsluttende tag og ikke, osv.

Lenke til kommentar

Har nå laget et eksempel som sorterer etter hvilken rekkefølge taggene opptrer i dokumentet.

 

<?php
$subject = 'nøstede <b[15]>hehe</b> tags, <b> <font size="12">det<i>te</b> er en <b></font>salig</i><a href="oi.denne.er.visst.ikke.lukket.html"> su<b>pp</b>e</b>';

function htmlparse($var) {

global $BODY, $TAG;

$BODY[ $var[2] ]  = array('tag' => $var[1], 'html' => strip_tags( $var[4] ), 'atr' => $var[3]);
$TAG[ $var[1] ][] = array('html' => strip_tags( $var[4] ), 'atr' => $var[3]);

return (strip_tags($var['4']) != $var['4']) ? $var['4'] : '';

}

function numtag($var) {

global $i;

return '<'.$var[1].'['.++$i.']'.$var[2].$var[3].'>';

}

$subject =  preg_replace_callback("#<([a-z0-9]+)( )?(.*?)?>#is", 'numtag', $subject);

while($subject = preg_replace_callback('#<([a-z0-9]+)\[([0-9]+)\] ?(.*?)?>(.*?)(</\1>|$)#is',"htmlparse",$subject)) {

if($old_subject == $subject)
 break;
else
 $old_subject = $subject;
 
}

ksort( $BODY );

print_r( $BODY );
?>

Lenke til kommentar

Interessant løsningsforslag. Men ser at du fortsatt ikke har hierarkisk informasjon.

 

Her er en kort kodesnutt som bruker en ferdig parser:

lindahl@holmenkollen(~)$ time perl -MHTML::TreeBuilder -e '$t=new_from_content HTML::TreeBuilder q{nøstede <b[15]>hehe</b> tags, <b> <font size="12">det<i>te</b> er en <b></font>salig</i><a href="oi.denne.er.visst.ikke.lukket.html"> su<b>pp</b>e</b>}; print $t->as_HTML;'
<html><head></head><body>nøstede hehe tags, <b> <font size=12>det<i>te</i></font></b> er en <b>salig<a href="oi.denne.er.visst.ikke.lukket.html"> su<b>pp</b>e</a></b></body></html>

real    0m0.141s
user    0m0.120s
sys     0m0.010s
lindahl@holmenkollen(~)$ time perl -MHTML::TreeBuilder -e '$t=new_from_content HTML::TreeBuilder q{nøstede <b[15]>hehe</b> tags, <b> <font size="12">det<i>te</b> er en <b></font>salig</i><a href="oi.denne.er.visst.ikke.lukket.html"> su<b>pp</b>e</b>}; $t->dump;'
<html> @0 (IMPLICIT)
 <head> @0.0 (IMPLICIT)
 <body> @0.1 (IMPLICIT)
   "nøstede hehe tags, "
   <b> @0.1.1
     " "
     <font size=12> @0.1.1.1
       "det"
       <i> @0.1.1.1.1
         "te"
   " er en "
   <b> @0.1.3
     "salig"
     <a href="oi.denne.er.visst.ikke.lukket.html"> @0.1.3.1
       " su"
       <b> @0.1.3.1.1
         "pp"
       "e"

real    0m0.145s
user    0m0.140s
sys     0m0.010s

 

Den første gangen dumper den ut HTML etter først å ha parset den.

 

Andre gangen gjør den en dump av parserobjektets innhold. Dvs ikke ren html, men mere enn debugdumping som viser hierarki og intern orgarniserng, indentert. Lasting av bibliotek og parsing går rimelig kjapt.

Lenke til kommentar

Jeg laget også en parser av en komplett side.

http://holmenkollen.dyndns.org/perl/komplett.cgi.html

 

Alt som er kommentert med røde kommentarer er relatert til logikk forbundet med oppslag i DOM vha parser.

 

resultatet blir slik:

http://holmenkollen.dyndns.org/cgi-bin/komplett.cgi

 

Å hente ut flere elementer er en formalitet. Koden er enkel og oversiktlig og lett å endre til nye html layouts.

Lenke til kommentar

Koden min mangler mange ting. Grunnen er ganske enkelt fordi jeg skrev den "on the fly" for å vise deg et eksempel på hvordan regulæruttrykk kan takle nøstede tags osv. Tror jeg har bevist dette nå.

 

Om jeg skulle skrevet en skikkelig HTML-parser som kunne gjort de samme oppgavene som parseren du referrer til, måtte jeg nok brukt en del mer tid samt at en god del mer kode måtte til.

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...