petterg Skrevet 4. desember 2004 Skrevet 4. desember 2004 Jeg er på jakt etter en effektiv parser som kan konvertere slike strenger til array: href="http://link.com" alt="he's a \"man\"" style=default heigth='30px' skal da gi samme arrayet som man ville fått med denne koden: $ar = array( "href" => "http://link.com", "alt" => "he's a \"man\"", "style" => "default"); (dette er bare eksempel for å illustrere utfordringen) Utfordringen her ligger i at value delen av attirbuttene kan være omgitt av anførselstegn (") eller apostrof (') eller dersom det bare er ett ord trenger det ikke være noen av delene. Teksten i value delen kan også inneholde både anførselstegn og apostrofer, så parseren må kunne takle at disse skal ignoreres når det står et escape tegn (\) forran. Noen som kjenner til en slik parser, eller har noen gode tips å komme med?
gnab Skrevet 5. desember 2004 Skrevet 5. desember 2004 Gjør susen denne tror jeg.. <?php $input = "href=\"http://link.com\" alt=\"he's a \\\"man\\\"\" style=default heigth='30px'"; preg_match_all("/(\w+)=/", $input, $names); $names = $names[1]; $values = preg_split("/(\w+)=/", $input, -1, PREG_SPLIT_NO_EMPTY); $output = array(); foreach ($names as $index => $name) { $output["$name"] = preg_replace("/(^[\"\']?)(.*)\\1$/", "\$2", trim($values[$index])); } var_dump($output); ?> Men hvor effektiv den er får noen andre ta seg av å vurdere..
petterg Skrevet 5. desember 2004 Forfatter Skrevet 5. desember 2004 Den funker jo bra den, helt til det kommer et = midt i teksten. Noen løsning for å ungå det problemet? f.x: $input = "alt=\"he=man\"";
RipZ- Skrevet 5. desember 2004 Skrevet 5. desember 2004 Om du tenker HTML burde man ikke tenke på escaping av verdier. For det skal ikke forekomme escaping av tegn i HTML. I stedet har man egne verdier for dette. alt="hei på deg \"SNUPPA\"" Dette er feil. Alt atributten vil bli tolket av nettleseren som om den inneholder "hei på deg \" og SNUPPA vil bli sett på som en egen attributt. Skal man ha med " må man erstatte dette tegnet med " for å få det riktig. Med andre ord burde det ikke være nødvendig for parseren å tolke slik tekst, da dette vil være feil med tanke på HTML-standaren. Det vil også hjelpe oss med å forenkle uttrykket betraktelig. Dette utrykket burde vel være tilstrekkelig? (\w+)="?(.*?)["| ]
gnab Skrevet 5. desember 2004 Skrevet 5. desember 2004 Tror det foreslåtte uttrykket der nok kommer til a ta med seg flere attributter fra HTML-koden i ett jafs.. Den følgende koden *krever* at attributtenes verdi er inneholdt i anførselstegn eller apostrofer, og escapes av anførselstegn og apostrofer kan inngå i verdien: <?php $input = "href=\"http://link.com\" alt=\"he's a \\\"he=man\\\"\" style=default heigth='30px'"; preg_match_all("/(\w+)=(\"[^\"\\\]*(\\\.[^\"\\\]*)*\"|\'[^\'\\\]*(\\\.[^\'\\\]*)*\')/", $input, $tmp); $names = $tmp[1]; $values = $tmp[2]; $output = array(); foreach ($names as $index => $name) { $output["$name"] = preg_replace("/^([\"\'])(.*)\\1$/", "\$2", $values[$index]); } var_dump($output); ?> Det tillates altså ikke verdier som style=default, da det her mangler anførselstegn eller apostrofer. Men skal du følge HTML-standarden støttes jo egentlig bare anførselstegn..
petterg Skrevet 6. desember 2004 Forfatter Skrevet 6. desember 2004 Jeg tok fram prinsippene med tilstandsmaskin fra hardware design og endte med denne koden: <?php function error_msg($msg) { echo "\n<h1>$msg</h1>\n"; } $str = "href=\"http://link.com\" alt=\"he's a \\\"he=man\\\"\" style=default heigth='30px'"; $state = 0; // s0:prekey, s1:key, s2:postkey, s10:preval s11:', s12:", s13:unquoted, s14:postval $len = strlen($str); $ar = array(); $key = ""; $val = ""; $activeescape = false; for($i = 0; $i <= $len; $i++) { switch ($state) { case 0: $key = ""; if(strlen(trim($str{$i}))) { $key = $str{$i}; $state = 1; } break; case 1: if(strlen(trim($str{$i}))) { if($str{$i} == "=") { $state = 10; } else { $key .= $str{$i}; } } else { $state = 2; } break; case 2: if(strlen(trim($str{$i}))) { if($str{$i} == "=") { $state = 10; } else { error_msg("error parsing attirbs at char $i: $str"); } } break; case 10: $val = ""; if(strlen(trim($str{$i}))) { if($str{$i} == "\"") { $state = 12; } else { if($str{$i} == "'") { $state = 11; } else { $val = $str{$i}; $state = 13; } } } break; case 11: case 12: if($activeescape) { $val .= $str{$i}; $activeescape = false; } else { if($str{$i} == "\\") { $activeescape = true; $val .= $str{$i}; } else { if(($str{$i} == "'" && $state == 11) || ($str{$i} == "\"" && $state == 12)) { $state = 14; } else { $val .= $str{$i}; } } } break; case 13: if($activeescape) { $val .= $str{$i}; $activeescape = false; } else { if($str{$i} == "\\") { $activeescape = true; $val .= $str{$i}; } else { if(strlen(trim($str{$i}))) { $val .= $str{$i}; } else { $state = 0; $ar[$key] = $val; } } } break; case 14: $ar[$key] = $val; $state = 0; break; } } print_r($ar); echo "$str\n"; ?> Mye kode, men den leser bare igjennom input en gang, og bør derfor være rask i drift. Har ikke klart å lure den til å gi feil resultat ennå.
Anbefalte innlegg
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 kontoLogg inn
Har du allerede en konto? Logg inn her.
Logg inn nå