Autor Zpráva
Charlie
Profil
Zdravím všechny,

nedávno jsem zde na diskusi představil můj text2html converter

Textization (na název nehleďte). Parsuje validně odstavce i seznamy, a to při jakémkoli nevalidním vstupu (snad). Problém nastává, když chci parsovat jednotlivé řádky a nahrazovat v nich nějaké znaky nějakými html tagy. Mám takovouhle proměnnou:
$tags = array(

"**" => "strong",
"//" => "em",
"^^" => "sup",
"__" => "sub",
"++" => "ins",
"--" => "del",
"??" => "cite"
);

Chtěl bych nahradit třeba "**text**" za "<strong>text</strong>". Tagy nahrazuji v této části scriptu:
foreach ($tags as $symbol => $tag) {

if (substr_count($row,$symbol) % 2) {
$row .= $symbol;
}
if (substr_count($row,$symbol) > 1) {
$count = substr_count($row,$symbol);
for ($i = 1; $i <= $count; $i++) {
$before = substr($row,0,strpos($row,$symbol));
$after = substr($row,strpos($row,$symbol)+strlen($symbol));
if ($i & 1) {
$row = $before."<".$tag.">".$after;
} else {
$row = $before."</".$tag.">".$after;
}
}
}
}

Problém nastává, když je vstup nevalidní, pak to háže i nevalidní výstup. Například z
**//text**//

tak to převede do
<strong><em>text</strong></em>

a to je nevalidní. Teď mám dvě možnosti. Buď budu konvertovat jen validní vstup, nebo to musím nějak automaticky zvalidnit. Druhá možnost se mi jeví jako lepší.

Řešili jste již někdy něco podobného?
Charlie
Profil
Tak jsem již vymyslel něco, ale stále to nevrací úplně validní kód:
$this->op = "";


$tags = array(
"**" => "strong",
"//" => "em",
"^^" => "sup",
"__" => "sub",
"++" => "ins",
"--" => "del",
"??" => "cite"
);

foreach ($tags as $tag) {
$this->op[$tag] = false; // žádný tag není otevřený
$this->tc[$tag] = 0; // každý se vyskytuje nulakrát
}

$position = array();

if (strlen($row) > 0) {
for ($i = 0; $i < strlen($row); $i++) { //procházení řetězce po znacích
if ($i > 100) break;
foreach ($tags as $tag => $tagg) {
$tp = strpos($row,$tag);
if ($tp == $i && $tp !== false) { //když je na aktuální pozici některý z nahrazovaných tagů ...
$at = $tag;
}
}


$entity = $at; // třeba "--"

$at = $tags[$at]; // třeba "del"

if (empty($at)) continue;


if (($this->tc[$at] / 2) == 0) { // základní replace
$replace = "<$at>";
$this->op[$at] = true;
} else {
$replace = "</$at>";
$this->op[$at] = false;
}

$this->tc[$at]++; // zvýší počet nalezených tagů o 1

$opened = array();
foreach ($this->op as $str => $status) {
if ($status === true && $str <> $at) {
$opened[] = $str; // zapíše všechny otevřené tagy do array
}
}

array_reverse($opened); otočí, aby se k replacu přidávaly v opačném pořadí

$bef = 0;
$aft = 0;

$before = substr($row,0,$i); // řetězec přet tagem

$after = substr($row,$i+strlen($entity)); // řetězec za tagem

foreach ($opened as $ope) {
$tags = array_flip($tags);
$ent = $tags[$ope];
$tags = array_flip($tags);
if (strpos($after,$ent) === 0) { // když se otevřený tag dále nenachází, tak ho uzavře
$replace = "</$ope>$replace";
$this->op[$ope] = false;
$after = substr($after,strlen($entity));
} elseif (strrpos($after,$ope) == strlen($after) - strlen($ope) - 1) { // když je otevřený tag přesně před tímto tagem, teď si uvědomuji, že je to bug
$replace = $replace."<$ope>";
$before = substr($before,0,-(strlen($ope)+2)); // ořízne tag před řetězcem
} else {
$replace = "</$ope>$replace<$ope>";
}
}

}
}

foreach ($this->op as $op => $vas) { //zavře, většinou ve špatném pořadí - bug
if ($vas === true) {
$row .= "</$op>";
}
$row = str_replace("<$op></$op>","",$row); // kdyby náhodou, odstraní prázdné tagy
}

Jak vidíte, tak to ještě není úplně validní, pokusím se s tím něco udělat a pak to sem zas hodím.
printf-jinde
Profil *
Jo, podobnou věc jsem řešil ale asi hrozně nešikovně:
prostě jsem procházel text znak po znaku a začínající tagy ukládal do zásobníku, ukončit šlo jedině tag, který je poslední v zásobníku, načež se ze zásobníku vymazal. Nepárové tagy se do zásobníku neukládají, ale já jsem s takovými nepracoval. Na konci textu se projel zásobník a ukončily se všechny neukončené tagy (tedy ty které zůstaly v zásobníku). Zásobník se dá velice snadno udělat s funkcemi pro práci s polem.
Asi to nejí nejelegantnější řešení, ale zato je IMHO spolehlivé.
Charlie
Profil
printf-jinde, však já jsem tam také implementoval zásobník. je to proměnná "op".
printf-jinde
Profil *
nojo, já jsem ten kód moc neprohlížel :-))
Toto téma je uzamčeno. Odpověď nelze zaslat.

0