MyBB.de Forum

Normale Version: Regulärer Ausdruck
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Hi MyBBCoder,

bei meinem Forenupgrade, an dem ich schon seit Monaten arbeite, komme ich langsam in die Endphase, wo nun allerhand kleinere Sachen noch umgesetzt werden müssen. Eine davon ist folgende:

Momentan gibt es in meinem Forum einen Thread-MyCode (und andere ähnliche MyCodes), der unter Angabe der TID zum entsrechenden Thread verlinkt (bsp: [thread=42]Text[/thread])

Diesen MyCode möchte ich nun folgendermaßen erweitern:
Es soll sowohl möglich sein, mit [thread=TID]Text[/thread] den Text des Links selbst zu bestimmen, als auch einfach nur ein [thread=TID] anzugeben, wo der Titel des Themas entsprechend aus der DB geholt wird. Das momentane Problem: Ich finde keinen passenden regulären Ausdruck, der diese MyCodes korrekt erkennt. Es wird entweder zu viel, oder das falsche geparst.

Beispiel:
_____
[thread=1] Dieser Text soll nicht geparst werden [thread=2]Titel von Thread-Link 2[/thread] Auch hier wieder kein parsen. [thread=3]
_____
Die blauen Stellen sind die standalone-Tags, wo anschließend dann der Titel des angegebenen Threads herausgesucht und als Link verwendet werden. Der grün markierte Teil ist die "klassische" Version, wo der Text des Links selbst mit angegeben wird.


Ich hatte mir gedacht, dass ich zuerst die Thread-Links raussuche, die eine Link-Text-Angabe besitzen (also die grünen), und über die übrig gebliebenen Thread-Codes (die ohne [/thread]) dann einen 2. regulären Ausdruck anwende (die blauen). Allerdings scheiter ich schon beim ersten:

Aktueller verwendeter Regulärer Ausdruck:
Code:
#\[thread=(\d+?)\](.*?)\[/thread\]#si

Erkennt bei obigen Beispiel aber folgendes:
[thread=1] Dieser Text soll nicht geparst werden [thread=2]Titel von Thread-Link 2[/thread]
Das heißt er nimmt direkt den ersten standalone-Tag (blau) und nutzt alles folgende bis zum [/thread] als Link-Text. Gewünscht ist aber (wie oben bereits erwähnt), dass nur der grüne Teil erkannt und entsprechend verarbeitet wird. Ich habe auch schon diverse andere Möglichkeiten probiert, aber entweder wird zu viel erkannt (wie hier), oder die klassische Variante (mit Text-Angabe) wird überhaupt nicht mehr erkannt Sad

Meine Fragen diesbezüglich:
Ist es überhaupt möglich, diese zwei Varianten an MyCodes zu haben (dh dass bei der kurzen Variante der End-Tag fehlt)?
Wenn ja, wie müsste ein entsprechender regulärer Ausdruck aussehen, der die Teile richtig erkannt?

Würde mich freuen, wenn mir jemand weiterhelfen kann Smile

MfG Zwoetzen
Das mit der Verschachtelung ist nicht so einfach möglich. Du könntest beide als einen BBCode angeben.
Meinst du damit, dass ich für beide Varianten einen regulären Ausdruck verwenden soll?

Das hatte ich auch schon versucht, aber kam nie auf das gewünschte Ergebnis. Wie gesagt: Entweder wurden die klassischen Tags zu weit gefasst (wie oben), oder gar nicht mehr erkannt und alles waren Stand-Alone-Tags...

Die Anzahl der regulären Ausdrücke wären mir eigentlich auch egal. Mir ist wichtig, dass zB das Beispiel oben korrekt erkannt wird, dh das ein Standalone-Thread nicht innerhalb eines klassischen-Thread-Tags erkannt wird. Ob das nun 1 oder 10 reguläre Ausdrücke sind... wayne ^^ (okay, es sollten nicht zu viele werden ^^)


Als Anmerkung vlt noch: Das ganze kommt in ein Plugin und wird entsprechend mit PHP ausgewertet. Kommt vlt nicht ganz so gut raus in meinem Post.
Verschachtelung sollte kein Problem darstellen, wenn man zuerst die Single-Tags durch die RegEx laufen lässt und dann die übrigen klassischen-Tags.

Für die Single-Tags:
Code:
#\[thread=(.+?)\]#is

Für die klassik-Tags:
Code:
#\[thread=(.+?)\](.+?)\[/thread\]#is
Wobei dieser von der Syntax dem des URL-BBCode ähnelt und etwas einfacher umsetzbar erscheint da man hier "nur" das passende Ersetzungs-Pattern für preg_replace() braucht. Smile

Zum experimentieren sei an der Stelle noch http://www.regex-tester.de/ erwähnt
So einfach deine Lösung scheint, hat sie dennoch einen sehr großen Fehler:
Nachdem der RegExp für die Standalones durchgelaufen ist, wird der zweite nie etwas finden, da die dazugehörigen Start-Tags bereits geparst wurden.

Das würde beim Beispiel oben bedeuten, dass ich direkt die Threads 1, 2 und 3 parse, indem ich den entsprechenden Titel aus der DB hole, und das [/thread] würde übrig bleiben. Zu dem findet der 2. RegExp aööerdings keinen Anfangs-Tag mehr, und lässt es stehen.

Haut somit von der Logik her schon nicht hin Wink
Trotzdem danke für deine Antwort Smile
Gut, ist vom logischen her ein Schnellschuss, da sich die Ausdrücke dank des = sehr ähnlich sind, es gibt da sicher Möglichkeiten.

Bei den PHP-Scripts mit denen ich sowas wie BBCode selbst eingebaut habe (mit Regulären Ausdrücken aus dem Internet) lief zwar alles gewissermaßen Fix von oben ab, aber solche Spezialfälle decke ich in meinem Code (bisher) nicht ab.

Man könnte natürlich in Anlehnung an XHTML-Notation hinter dieses Single-Tag noch ein "/" setzen, vergleichbar wie bei einem IMG-Tag und so die Klippe mit dem Logik-Problem umschiffen beim Single-Tag.
Code:
#\[thread=(.+?)\/\]#is

Der Beispiel-Text würde dann so lauten:
Code:
[thread=1/] Dieser Text soll nicht geparst werden [thread=2]Titel von Thread-Link 2
[/thread] Auch hier wieder kein parsen. [thread=3/]
Ja, an diese Möglichkeit hatte ich auch bereits gedacht, nur würde ich es gerne bevorzugen, die oben beschriebene Variante zu haben, indem quasi der End-Tag (und der Text dazwischen) entfällt, um auf die verkürzte Variante zu kommen.

Wenn sich keine entsprechenden Ausdrücke finden lassen, muss ich wohl oder übel auf die /-Methode zurückkommen. Aber noch ist nicht alle Tage abend, vielleicht findet sich noch eine Lösung Smile

(Ich vermute nämlich, dass der / früher oder später vergessen werden wird, gerade von Usern, die keine Kenntnisse in (X)HTML&Co haben.)


Ein anderer Ansatz wäre wohl folgender:
Man verzichtet von Anfang an auf die regulären Ausdrücke, und sucht "zu Fuß" selbst den String nach signifikanten Stellen (wie "[thread=" und der darauffolgenden "]" bzw. "[/thread]" als Endtag) ab. So kann man je nach Auftreten der einzelnen Funde entscheiden, ob es nun Standalone oder klassisch ist.
Klar, der Aufwand ist entsprechend höher, aber so könnte man das gewünschte Resultat erreichen.
Oder man macht es so: [thread=id|text]
Dabei ergibt sich auch 2 Werten , wenn der Text da ist - kann man via Kontrollblock auch recht simpel unterscheiden ob das gesetzt wurde oder nicht und dann seine Funktion dahinter entsprechend ausbauen.

In jedem Falle, egal ob mit oder ohne dem "/" oder wier hier eben beschrieben Weg. Der User muss zumindest am Ende wissen wie's geht und dies umsetzen können, da sollte ein netter Hinweis an den User eher was bringen als das er XHTML oder ähnliches kennen muss, denn es ist ja sozusagen eine "Vorgabe" des Plugin.

Man könnte auch eine Variante schreiben die via preg_split() alle Start-Tags aussortiert bis zum nächsten Vorkommen, Ergebnis wäre ein Array was man dann via foreach-Schleife durchlaufen lässt und dabei die Suche nach dem Ende des Tags macht und das notwendige veranlasst.

.. hier gibt es vielleicht auch besseres, wobei eine Suche Zeichen für Zeichen sicher etwas Rechenzeit kostet und die Regulären Ausdrücke fixer sind.
Auf preg_split() war ich auch schon gestoßen. Ich habe mir nun etwas Zeit genommen, und nochmal alle Varianten durchdacht, und habe mich für folgenden Ansatz entschieden, da er recht einfach zu realisieren war Big Grin

Dabei habe ich die erste Idee wieder aufgegriffen, zuerst die Klassischen und danach die Standalone-Tags zu parsen:
PHP-Code:
if (preg_match_all("#\[(forum|post|thread|user)=(\d+?)\](.*?)\[/\\1\]#si"$message$match))
{
    
$full $match[0][$i];
    
$tag  $match[1][$i];
    
$id   $match[2][$i];
    
$text $match[3][$i]; 
(Anmerkung: Hier wurde neben dem Thread-Tag auch schon Post, User und Forum eingefügt, die ähnlich funktionieren)

Nun tritt natürlich der oben genannte Fehler auf, dass die klassischen Tags teilweise nicht richtig erkannt werden. Mit einem weiteren RegExp habe ich dieses Problem "manuell" korrigiert (Es wird der letzte Standalone-Tag aus dem Text rausgesucht, da dieser ja zu unserem klassischen Tag gehört):
PHP-Code:
    if (preg_match("#\[{$tag}=(\d+)\](?!.*\[{$tag}=\d+\])(.*)#si"$text$fix))
    {
        
$full "[{$tag}={$fix[1]}]{$fix[2]}[/{$tag}]";
        
$id   $fix[1];
        
$text $fix[2];
    } 
Das bedeuted, dass wir an dieser Stelle garantiert die klassischen Tags, und keinen Standalone Tag mehr dazwischen.

(Den Teil, wo jetzt das st_replace() zum "übersetzen" angewendet wird, hab ich mal weggelassen. Der sollte klar sein ^^)

Nachdem nun die klassischen Tags alle beseitigt sind, sind alle übrigen Standalone-Tags, und können einfach geparst werden:
PHP-Code:
if (preg_match_all("#\[(forum|post|thread|user)=(\d+?)\]#si"$message$result)) 
... gefolgt von allerhand Anweisungen zum Raussuchen der entsprechenden Titel der Threads/Posts/Foren/User und dem eigentlichen Parsen ^^

Danke nochmal für deine Unterstützung, alexZero Smile
Wenn ich das ganze komplett fertig habe, werde ich das ganze als Plugin zur Verfügung stellen Wink
(Bis jetzt werden noch jegliche Rechte ignoriert, dh die Titel von Themen in versteckten Foren sind bis jetzt noch sichtbar...)

MfG Zwoetzen