BB-Code: Nicht HTML-konforme Verschachtelung lösen

  • Ich arbeite gerade an einem BB-Code-Parser. Ich verwende dabei unter anderem folgende BB-Codes:

    Code
    [b] für fett
    [i] für kursiv
    [u] für unterstrichen
    [left] für einen linksbündigen Absatz
    [center] für einen zentrierten Absatz
    [right] für einen rechtsbündigen Absatz
    [indent] für einen eingerückten Absatz
    [quote] für ein Zitat


    Damit beim Parsen kein ungültiges HTML erzeugt wird, muss der gesamte Text vor dem Parsen so verändert werden, dass wenn , oder einen absatzerzeugenden Code umklammern, [b],[i] oder [u] vor dem Absatz geschlossen werden, nach öffnen des Absatzes wieder geöffnet werden, am Ende des Absatzes wieder geschlossen werden und dann nach dem Absatz wieder geöffnet werden. Wenn ein Absatz also z.B. fett dargestellt werden soll, dürfen die b-Tags nicht außerhalb des Tags, der den Absatz erzeugt, stehen, sondern müssen davor geschlossen werden und dann innerhalb des Absatzes wieder geöffnet werden.

    Ein einfaches Beispiel wäre:

    Code
    [b]Text1[center]Text2[/center]Text3[/b]


    Soll werden zu...

    Code
    [b]Text1[/b][center][b]Text2[/b][/center][b]Text3[/b]

    Das ganze sollte aber auch im folgenden Fall funktionieren:

    Code
    [b]Text1[i]Text2[u]Text3[center]Text4[/center]Text5[/i]Text6[right]Text7[/right]Text8[/b]Text9[/u]


    Soll werden zu...

    Code
    [b]Text1[i]Text2[u]Text3[/u][/i][/b][center][b][i][u]Text4[/u][/i][/b][/center][b][u][i]Text5[/i]Text6[/u][/b][right][b][u]Text6[/u][/b][/right][u][b]Text8[/b]Text9[/u]


    Ich habe den Parser eigentlich bereits vollständig fertig. Mir fehlt eben nur noch eine Funktion, die den Text wie oben angegeben umformt. Ich habe recht lange mit preg_replace herumexperimentiert, bin jedoch nicht zu einem zufrieden stellenden Ergebnis gekommen. Es wäre also toll, wenn jemand eine Idee hätte, wie man das Problem lösen kann oder vielleicht jemand weiß, wie das bei anderen Parsern gemacht ist. Vielen Dank bereits im Voraus,
    Daniel

  • Code
    function bbencode($message) {
    	// [code] and

    for posting code (HTML, PHP, C etc etc) in your posts.
    $matchCount = preg_match_all("#\[code\](.*?)\[/code\]#si", $message, $matches);

    for ($i = 0; $i < $matchCount; $i++)
    {
    $currMatchTextBefore = preg_quote($matches[1][$i]);
    $currMatchTextAfter = htmlspecialchars($matches[1][$i]);
    $message = preg_replace("#\[code\]$currMatchTextBefore\[/code\]#si", "<TABLE BORDER=0 ALIGN=CENTER WIDTH=85%><TR><TD>Code:<HR></TD></TR><TR><TD><PRE>$currMatchTextAfter</PRE></TD></TR><TR><TD><HR></TD></TR></TABLE>", $message);
    }

    //

    Zitat

    and

    for posting replies with quote, or just for quoting stuff.
    $message = preg_replace("#\[quote\](.*?)\[/quote]#si", "<TABLE BORDER=0 ALIGN=CENTER WIDTH=85%><TR><TD>Quote:<HR></TD></TR><TR><TD><BLOCKQUOTE>\\1</BLOCKQUOTE></TD></TR><TR><TD><HR></TD></TR></TABLE>", $message);

    // and for bolding text.
    $message = preg_replace("#\[b\](.*?)\[/b\]#si", "\\1", $message);

    // and for italicizing text.
    $message = preg_replace("#\[i\](.*?)\[/i\]#si", "\\1", $message);

    // and for italicizing text.
    $message = preg_replace("#\[u\](.*?)\[/u\]#si", "<U>\\1</U>", $message);
    // http://http://www.phpbb.com</a> code..
    $message = preg_replace("#\[url\](http://)?(.*?)\[/url\]#si", "<A HREF=\"http://%5c%5c2%5c" TARGET=\"_blank\">\\2</A>", $message);

    // phpBB code..
    $message = preg_replace("#\[url=(http://)?(.*?)\](.*?)\[/url\]#si", "<A HREF=\"http://%5c%5c2%5c" TARGET=\"_blank\">\\3</A>", $message);

    // user@domain.tld code..
    $message = preg_replace("#\[email\](.*?)\[/email\]#si", "<A HREF=\"mailto:\\1\">\\1</A>", $message);

    // code..
    $message = preg_replace("#\[img\](http://)?(.*?)\[/img\]#si", "<IMG SRC=\"http://%5c%5c2%5c">", $message);
    // $message = preg_replace("#\[img\](.*?)\[/img\]#si", "<IMG SRC=\"\\1\">", $message);


    // unordered list code..
    $matchCount = preg_match_all("#\[list\](.*?)\[/list\]#si", $message, $matches);

    for ($i = 0; $i < $matchCount; $i++)
    {
    $currMatchTextBefore = preg_quote($matches[1][$i]);
    $currMatchTextAfter = preg_replace("#\[\*\]#si", "<LI>", $matches[1][$i]);

    $message = preg_replace("#\[list\]$currMatchTextBefore\[/list\]#si", "<UL>$currMatchTextAfter[/list]", $message);
    }

    // ordered list code..
    $matchCount = preg_match_all("#\[list=([aA1I])\](.*?)\[/list\]#si", $message, $matches);

    for ($i = 0; $i < $matchCount; $i++)
    {
    $currMatchTextBefore = preg_quote($matches[2][$i]);
    $currMatchTextAfter = preg_replace("#\[\*\]#si", "<LI>", $matches[2][$i]);

    $message = preg_replace("#\[list=([aA1I])\]$currMatchTextBefore\[/list\]#si", "[list=1]$currMatchTextAfter[/list]", $message);
    }

    // alle \n durch ein BR ersetzen (Zeilensprung)
    $message = str_replace("\n", "<BR \>\n", $message);

    return($message);
    }[/code]


    ist zwar etwas overkilled das ganze aber geht.

  • Also erstmal vielen Dank für deine Hilfe. Aber ich glaube die Funktion löst mein Problem nicht. Einen BB-Code Parser habe ich ja bereits. Das einzige was mir noch fehlt ist eben eine Funktion, die vor dem eigentlichen Parsen die Formatierungsbefehle wie b,i und u korigiert, so dass z.B. aus...

    Code
    [b]Text1[i]Text2[u]Text3[center]Text4[/center]
    Text5[/i]Text6[right]Text7[/right]Text8[/b]Text9[/u]


    ... folgendes wird:

    Code
    [b]Text1[i]Text2[u]Text3[/u][/i][/b][center][b][i][u]Text4[/u][/i][/b][/center]
    [b][u][i]Text5[/i]Text6[/u][/b][right][b][u]Text6[/u][/b][/right][u][b]Text8[/b]Text9[/u]

    Aber wie macht man so was?

  • aso kommen wir erstmal zur preisfrage was diese ganze aktion soll.

    also das einzigste was du beachten musst, das alle geöffneten tags geschlossen werden müssen bevor man ein anderes öffnest.

    und das macht man eigentlich schon mit dem script welches den bbcode erstellt.

    da das ganze wie du es dir denkst viel viel zu aufwendig währe um es bei jedem anzeigen durchlaufen zu lassen.

  • Also das ganze ist so:
    Ich arbeite an einem Skript, dass den BB-Code zu HTML-Code umformt. Ich habe mir dafür folgenden Parser geholt http://www.christian-seiler.de/projekte/php/bbcode/index.html.

    Das Problem was ich jetzt habe, ist dass wenn jemand z.B.

    Code
    [b][center]Hallo[/center][/b]

    eintippt, das zu folgendem wird:

    Code
    [b]<p style="text-align:center">Hallo</p>[/b]

    Das wäre aber kein gültiges HTML und würde bei komplizierteren Texten dazu führen, dass der Code auch nicht wie gedacht interpretiert wird. Deshalb brauche ich eine Funktion, die vor dem eigentlichen Parsen den Code entsprechend umformt. Bei obigen Beispiel würde das dann so aussehen:

    Code
    [b][/b][center][b]Hallo[/b][/center][b][/b]


    Die leeren Tags würden dann von einer anderen Funktion später gelöscht. Ich habe auch bereits eine Funktion geschrieben, die obiges Beispiel richtig umsetzt. Mein Problem ist aber, dass dann aus...

    Code
    [b][center]Text1[/center][right]Text2[/right][/b]


    ... letztendlich folgendes wird:

    Code
    [center][b]Text1[/center][right]Text2[/b][/right]

    Das wiederum ist ja erst recht kein richtiger Code. Es gibt auch noch weitere Beispiele, bei denen meine Funktion nicht richtig funktioniert. Deswegen brauche ich eine Funktion, die den Code in jedem Fall richtig umformt. Leider habe ich keine Ahnung wie dafür der reguläre Ausdruck aussehen müsste und ob das nicht auch anders geht. Wäre echt nett, wenn mir dabei jemand helfen könnte.

  • also wofür benötigst du das ganze jetzt genau?1

    PS.... allein mit regex kommst du da definitv nicht weiter.

    da muss da am besten eine etwas umfangreiche klasse her.

    diese würde ich dann so aufbauen,

    das du deinen Text anhand von regex zerlegst und in einer array ablegst. das heist

    code->*****
    type->bold

    wüstest du wie soetwas zu lösen ist ?!

    also das heist alle bbcodes erstmal entfernen und dann halt wieder geordnet zusammensetzen.

  • Der Parser den ich mir geholt habe funktioniert ja auch so. Keine Ahnung, ob ich das aber auch selber hinkriege. Gibt es denn keine Möglichkeit, dass mit preg_replace und regulären Ausdrücken zu machen? Das Hauptproblem ist denke ich mal, dass die regulären Ausdrücke immer auf das größtmögliche bezogen werden. Das müsste bei mir eigentlich umgekehrt sein. Kann man das irgendwie ändern?

  • nein das kannst du definitiv nicht mit regex lösen wie den auch...

    da verstehst du das mit den regext nicht so ganz.

    du kannst mit denen doch auch nur fester vorkommnisse ändern.

    oder willst du etwa mittels regex alle möglichen verdrehungen berücksichtigen ?!

    da musst du schon was anderes aufweisen.

    du musst immer darandenekn das die maschiene nicht wies wie es gehört.

    da hilft meienr meinung nach nur schritweises auslesen und wieder ordentlich zusammenbauen.