PHP Smilies richtig erkennen

joe67

Cadet 4th Year
Registriert
Jan. 2007
Beiträge
96
Hallo,

ich habe ein Problem dessen aktuelle Lösung mir nicht wirklich gefällt. Ich möchte in einer von mir programmierten Shoutbox Smilies verwenden. Dazu habe ich folgenden Code implementiert:

PHP:
function Smilie2Image( $text )
{   

	$Smilies = array( '/(?<!>):\)/'
			, '/\^\^/'
			, '/:D\b/'
			, '/(?<!>):\(/'
			, '/:,\(/'
			, '/>:\(/'
			, '/:P\b/'
			, '/;\)/'
			, '/>:\)/'
			);


	$Images = array(  '<img src="'.SUB_DIR.'smilies/smile.gif">'
			, '<img src="'.SUB_DIR.'smilies/smile.gif">'
			, '<img src="'.SUB_DIR.'smilies/biggrin.gif">'
			, '<img src="'.SUB_DIR.'smilies/frown.gif">'
			, '<img src="'.SUB_DIR.'smilies/cry.gif">'
			, '<img src="'.SUB_DIR.'smilies/angry.gif">'
			, '<img src="'.SUB_DIR.'smilies/tongue.gif">'
			, '<img src="'.SUB_DIR.'smilies/wink.gif">'
			, '<img src="'.SUB_DIR.'smilies/impish.gif">'
			);

   $text = preg_replace( $Smilies, $Images, $text );
    return $text;
  }

Damit preg_replace z.B. die Muster
Code:
:(
und
Code:
>:(
nicht fehlerhaft interpretiert und aus beidem das hier macht :( >:(, habe ich die RegExp (?<!>):\( für den traurigen Smilie implementiert. Damit wird der smilie nur ersetzt wenn das Zeichen '>' nicht davor steht und gleichzeitig wird aus dem zweiten Smilie ein wütendes Gesicht so wie dieses: :mad:.

Soweit so gut, das ganze funktioniert perfekt. Jetzt möchte ich aber eine Liste der Smilies evtl. aus einer Datei oder DB auslesen. Dort sollen aber nur die Grafikdateien und die ASCII-Entsprechungen hinterlegt sein also z.B.:

Code:
:(    frown.gif
>:(  angry.gif

Gibt es jetzt eine Möglichkeit Texte zu parsen in denen diese beiden ASCII-Smilies eindeutig erkannt werden, ohne dass ich komplexe Regular Expressions mit "Negative Lookbehind-Assertion" daraus machen muss und ohne dass es zu der oben angesprochenen Interpretation kommt?

Ich hoffe ich habe einigermaßen verständlich machen können, worum es mir geht.

j o e
 
Hi,

da es eigentlich rein mit der Anzeige zu tun hat würde ich generell einen falschen Ansatz attestieren. Wieso machst du sowas Serverseitig und nicht beim Client (JavaScript)? Oder verstehe ich dein Vorhaben gerade komplett falsch?

Du hast eine Shoutbox und wenn ich da eine bestimmte Zeichenkombination eingebe, soll ein Smiley draus werden. Richtig soweit?

VG,
Mad
 
Vorausgesetzt, die Werte in einer Zeile der Datei sind mit Tab getrennt:

PHP:
$smile_file = fopen("datei.txt", "r");
$s_liste = array();
while($s_liste[] = explode("\t", fgets($smile_file))) {
	continue;
}
fclose($smile_file);

Ergibt ein mehrdimensionales Array $s_liste.

Code:
Array[0] = 
	Array {
		[0] = :)
		[1] = smile.gif
	}
Array[1] =
	Array {
		[0] = :(
		[1] = sad.gif
	}
....

Alle Angaben ohne Gewähr, da Trockenübung ;)

JavaScript hat den Nachteil das man es einfach Abschalten kann. Daher sollte es sowieso immer eine "Fallback" Lösung geben.

Gruß
Spike S.
 
Hi,

ah ok, jetzt verstehe ich. Ich mache das Zeichen, der Server macht daraus dann ein img-tag mit src = sad.gif z.B., oder? Ok, das ist natürlich was anderes :)

Klar, JS hat immer den Nachteil, dass der Client sich das aussuchen kann. Stimmt schon :) Aber: Wenn ich meine Seite nunmal auf JS auslege dann gibt es da eben einfach kein Fallback ;) Ich habe z.B: komplette Seiten im Sencha-Framework gebaut, da kann ich nicht hinterher noch eine Fallbacklösung machen :)

VG,
Mad
 
Anscheinend habe ich mich nicht ausreichend präzise ausgedrückt.

@Spike S.: Ich weiß schon wie man aus einer Datei liest. Das ist gar nicht mein Problem.

@Madman1209: Richtig, der User schreibt ein ASCII-Smilie, der Server speichert es in der DB und beim Auslesen aus der DB interpretiert er das ASCII-Smilie und ersetzt es durch einen img-tag. Das ganze per PHP, kein Javascript.

Das Problem ist, dass der eine ASCII-Smilie quasi eine Untermenge des anderen ist, und PHP mittels preg_replace auf diese gemeinsame Untermenge anspricht.

Das hier sind die ASCII-Smilies:
Code:
:(      >:(
Und das hier die Ergebnisse: :( >:(
Man beachte, dass beides mal die gleichen img-Tags erzeugt werden und beim zweiten Smilie das Zeichen '>' nicht als Bestandteil des ASCII-Smilies berücksichtigt wird.
Das eigentlich gewünschte Ergebnis sieht aber so aus: :( :mad:

Deshalb musste ich ja mit Regular Expressions und der Lookbehind-Assertion arbeiten. Aber genau das möchte ich nicht tun, weil ich nicht von Hand Regular Expressions für die ASCII-Smilies erzeugen will, sondern die ASCII-Smilies einfach aus einer Datei auslesen will, ohne dass es regular Expressions sind.

j o e
 
Jetzt scheint es mir klarer....

Ich würde in dem Fall gar nicht groß mit irgendwelchen Sonderzeichen arbeiten und statt dessen intern mit eindeutigeren Bezeichnern arbeiten. Sprich, beim speichern einmal alles in beispielsweise "[ANGRY]" oder "n3j4bt533bogb3" (ohne ") ummünzen und beim ausgeben dann einfach nach der Zeichenkette suchen. Mit Arrays bist du ja vertraut.

Beim einlesen müsste man dann nur noch die Reihenfolge beachten. Erst 'angry', dann 'sad'. Vermutlich reicht es schon die Position der beiden Smilies in den Arrays zu tauschen.

Gruß
Spike S.

P.S.: Warum überhaupt reguäre Ausdrücke? Bei PHP ist es doch Egal was für Zeichen in einer Zeichenkette enthalten sind, solange es kein \X oder { ist. Oder?
 
Das Umwandeln vor dem Speichern bringt wahrscheinlich keine Abhilfe wenn das Parsen des Strings generell nicht so funktioniert wie ich will. Wann ich parse spielt da keine Rolle.

Auch habe ich schon versucht, die Reihenfolge der Strings im Array zu tauschen. Leider ohne Erfolg.

Warum ich Regular Expressions verwende? Bisher nur dafür, dass ich eben per Lookbehind-Assertion erkennen kann, dass der eine Smilie das Zeichen '>' nicht enthält. aber ich will ja auf Regular Expressions verzichten, das ist ja gerade mein Anliegen

j o e
 
Nur beim speichern REGEX-parsen reduziert die Häufigkeit dieses umständlicheren parsens, da str_replace performanter ist.

Abgesehen davon, würde es mich jetzt aber wundern, wenn die X_replace Funktionen nicht der Reihe nach die Arrays durchlaufen. Meiner Meinung nach müsste das auch mit str_replace ausreichend funktionieren, wenn die Smilies absteigend nach Anzahl der Zeichen sortiert durchlaufen werden.

Code:
$Smilies = array( ">:(", ":,(", ":(", .....);

Notiz am Rande: Das Caching vom Browser und Server hat mich schon öfter länger nach Problemen suchen lassen als Notwendig gewesen wär.

Gruß
Spike S.
 
ich finde deinen ansatz an sich recht aufwendig
mach doch ein assozioatives array:

Code:
$smileys = array(
		':)' => 'smiley.gif',
		'>:)' => 'angry.gif',
		':(' => 'sad.gif',
		':((' => 'evenmoresad.gif'
	);

smileycode = ':)';
echo $smileys[$smileycode];

und wenn du dieses array in eine datei auslagerst, kannst du es nach bedarf includen und dann recht einfach durchiterieren und daraus eine datei erzeugen bzw. eine liste dieses arrays ausgeben

Wenn die Daten in einer vernünftigen CSV (z.b. TAB als trenner, der kommt hoffentlich nicht in Smileys und Pfaden vor), aus dieser ein Array erzeugen:

dateizeile:
Code:
":)	smiley.gif"

Code:
$hilfsarray = explode("\t"; $dateizeile);
$smileys[$hilfsarray[0]] = $hilfsarray[1];
 
Zuletzt bearbeitet:
Regexes sind in dem Fall unnoetig. Du musst einfach nur auf die Reihenfolge der replace-Operationen achten und gut ist es. Eine Map (wie rumbalotte vorgeschlagen hat) duerfte am sinnvollsten sein.
 
character schrieb:
Du musst einfach nur auf die Reihenfolge der replace-Operationen achten und gut ist es.
So hätte ich mir das auch gedacht. Einfach das ">:(" vor dem ":(" ersetzen und es sollte so funktionieren, wie du willst.
 
Ganz so einfach wie Rumbalotte es vorschlägt geht es leider nicht, da ich ja eine ganze Textzeile parsen muss in der beliebig viele Smilies vorkommen können.

Allerdings ist es wirklich wesentlich cleverer bereits beim Speichern zu parsen, weil es den Server in der Tat enorm entlastet.

Die Reihenfolge zu ändern hat jetzt doch funktioniert. Ob ich da echt auf irgendwelches Caching reingefallen bin, oder mich irgendwie betriebsblöd angestellt habe kann ich jetzt leider nicht beurteilen. In jedem Fall danke ich euch allen für eure hilfreichen Kommentare. Funktioniert alles so wie ich es mir gewünscht habe.

j o e
 
joe67 schrieb:
Allerdings ist es wirklich wesentlich cleverer bereits beim Speichern zu parsen, weil es den Server in der Tat enorm entlastet.


Würde ich nicht machen, der Ansatz ist doch merklich unflexibler und du holst dir Abhängigkeiten in die DB. Wenn Performance ein Problem sein sollte, dann cache hinterher lieber den Output.
 
Zurück
Oben