Entwicklerblog #3 buildersleague.de
Im folgenden Blogeintrag geht es um die Hintergründe und Probleme bei der Entwicklung eines Bukkit-Plugins.
Unsere Developerin Demostenes gibt uns diese Woche einen kleinen Einblick in ihr Leben ans Entwickler. Vielen Dank an sie, für diesen ausführlichen Beitrag.
Freitextfelder sind böse
Wisst ihr, wie man einem Programm beibringt, eine in ein Freitextfeld eingegebene E-Mail-Adresse auf Gültigkeit zu überprüfen? Ich präsentiere den regulären Ausdruck, der dem offiziellen Standard entspricht:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])
Wunderschön, nicht wahr?
Und selbst dieses Monster erkennt offensichtlich ungültige E-Mail-Adressen wie [email protected] nicht, weil es z.B. die gültigen Top-Level-Domains nicht kennt.
(Quelle: http://www.regular-expressions.info/email.html)
Was hat das mit Minecraft-Plugins zu tun?
Nun, wenn man wie ich den Auftrag für ein chatbeaufsichtigendes Plugin erhält, (leider) eine ganze Menge. Denn die Eingabe erfolgt über ein Freitextfeld und ich weiß nicht einmal, ob ich einen Satz, eine E-Mail-Adresse oder etwas völlig anderes zu erwarten habe.
Warum bin ich denn jetzt geflogen?
Es ist schon einige Jahre her, da war ich in einem Chat unterwegs. Mitten im Gespräch mit einigen Bekannten wurde plötzlich eine meiner Nachrichten zensiert. Ich war verwirrt. Eigentlich hatte ich nur auf den aufgebrachten Gemütszustand eines männlichen Mitchatters hinweisen wollen, aber der Wortfilter sah das wohl anders.
„Er ist ein wenig gereizt.“
Einige Zeit danach versuchte ich erneut, diesen Satz in besagtem Chat zu schreiben und siehe da: Ich konnte es. Offenbar hatte der Wortfilter gelernt, bestimmte Dinge zu differenzieren.
Doch wie gestaltet man einen intelligenten Wortfilter? Das ist gar nicht so einfach. Macht man ihn zu lasch, schaffen es vielleicht zu viele sperrwürdige Nachrichten in den Chat. Macht man ihn zu streng, werden möglicherweise harmlose Gespräche zensiert und die User sind zu Recht genervt.
Versuchen wir also zunächst die offensichtlichen Fälle abzudecken. Es gibt nun einmal Wörter, die man nicht im Chat verwenden sollte. Also eine Liste mit schlimmen Begriffen her und alle Wörter einer Nachricht mit den Einträgen der Liste vergleichen.
Hier beginnen bereits die Unterschiede zwischen einem Menschen, der eine Nachricht überprüft und einem Programm. Was ist ein Wort? Für einen Menschen ist das offensichtlich, aber das Programm sieht die Nachricht als eine Kette von aneinandergereihten Zeichen (im weiteren Verlauf als String bezeichnet) und kennt keine Wort-Einheit. Der String muss zuerst bearbeitet werden, um ihn in einzelne Wörter einteilen zu können.
An dieser Stelle muss man überlegen, ob man z.B. Bindestriche in einem Wort entfernt oder nicht. Außerdem sollte man darauf achten, dass Chatnachrichten sich meist nur grob an den Regeln der Sprache orientieren, also sollte der Unterschied zwischen Groß- und Kleinbuchstaben vernachlässigt werden. Auch hier ist zu beachten: Ein Mensch weiß, dass ‚A‘ und ‚a‘ denselben Buchstaben meint, für das Programm sind dies unterschiedliche Zeichen.
Wie man sieht, sind hier schon einige Punkte zu beachten, dabei wollten wir doch einfach nur prüfen, ob ein Wort aus einer Liste in der Nachricht vorkommt. Geht das nicht einfacher?
Ja und nein. In Java gibt es vorgefertigte Methoden, die prüfen können, ob ein Wort in einem String vorkommt oder besser gesagt, ob ein Teil-String in einem String vorkommt. Und hier liegt ein Knackpunkt. Je nach gewählter Methode wird unter Umständen nur geprüft, ob irgendein Teil der Nachricht mit einem Wort aus der Liste übereinstimmt. Ein Beispiel:
Man möchte nicht, dass das Wort „anal“ in einer Chatnachricht vorkommt. Bearbeitet man den String selbst und überprüft einzeln die extrahierten Wörter, hat jemand, der über Kanalarbeiter schreibt, vermutlich keine Probleme. Prüft man dagegen mit einer Methode wie contains (gibt an, ob ein bestimmter Teil-String in einem String vorkommt) die komplette Nachricht, wird diese gesperrt.
Andererseits gibt es auch so eindeutig unerwünschte Teil-Strings, dass eine Überprüfung mit contains genügen und die Nachricht zu Recht gesperrt werden würde. Hier muss man abwägen und untersuchen, wie sich die im Chat verwendete Sprache verhält. Dies ist überhaupt ein wichtiger Punkt: Welche Sprachen erwarte ich, welche möchte ich filtern und was muss ich dabei beachten?
Ähnlich wie im oben genannten Beispiel soll niemand bestraft werden, weil er einen Konsekutivsatz korrekt mit ‚dass‘ schreibt, nur weil bestimmte englische Wörter nicht erlaubt sind. Ein Programm, das keine Wörter kennt, kann aber natürlich noch weniger unterscheiden, welche Sprache gerade in einem String übermittelt wurde und welche unpassenden Wörter es wann beachten muss. All das muss der Programmierer dem Programm „beibringen“.
Nur zur Erinnerung: Wir sind immer noch bei unserem ersten Punkt, um einen Chatfilter zu erstellen. Wenn wir alles richtig gemacht haben, kann unser Programm nun bestimmte Wörter- und Wortschnippsel erkennen und entsprechende Nachrichten sperren. Was passiert, wenn jemand ein schlimmes Wort tarnt, indem er einen Buchstaben mit einem * oder Ähnlichem ersetzt? Richtig: Gar nichts. Was kann man dagegen tun?
Hier geht der Spaß richtig los.
Man könnte versuchen derartig getarnte Konstrukte zu erkennen und z.B. mit regulären Ausdrücken zu arbeiten. Oder man berechnet so lustige Dinge wie die Levenshtein-Distanz für die Teil-Strings der Nachricht und die Wörter in der Liste. Natürlich besteht immer die Gefahr, dass dadurch zu viele falsche Treffer in Nachrichten gefunden und zu viele Nachrichten zensiert werden. Außerdem sollte man auch im Auge behalten, dass bestimmte Operationen unter Umständen sehr rechenintensiv sind und zu einer großen Last für den Server werden, denn gerade der Chat kann sehr stark frequentiert sein und den programmierten Aufwand betreibt man für jede einzelne Nachricht, die geschrieben wird.
So schnell kann ein simpel klingender Auftrag zu einem komplexen Problem werden, das im Rahmen eines Minecraft-Plugins vielleicht gar nicht lösbar ist, ohne einen Server dabei lahmzulegen. Als ich damals den Auftrag für die erste Version des Antispam-Plugins bekam, hätte ich nicht erwartet, einmal vor solchen Problemen zu stehen. Besonders, weil ich zunächst ganz andere Probleme hatte, da es sich um mein erstes Minecraft-Plugin handelte und ich erst lernen musste, wie man so etwas überhaupt erstellt. Da ging es beispielsweise darum, störende Leerzeichen (yaml ist da sehr empfindlich) in Konfigurationsdateien als Fehlerursache ausfindig zu machen und zu entfernen. Später habe ich dann gelernt, wie man einen Server zum Abstürzen bringen kann - allerdings eher unfreiwillig. Doch auch diese Kinderkrankheit ist überstanden und das Plugin hat einige Versionswechsel hinter sich gebracht. Wie ich Faff kenne, werden auch noch viele weitere folgen, denn das könnte man ja noch einbauen und das noch verbessern und wie wäre es denn damit…?
Ich für meinen Fall bin gespannt, was noch alles aus meinem Plugin wird und hoffe, dass euch dieser kleine Einblick ins Entwicklerleben gefallen hat :3
Wir hoffen euch hat dieser kleine Einblick mindestens genauso gut gefallen wie uns! Anregungen und Kommentare bitte in unser Forum.
Verfasser: Faffling94 Vielen Dank an Demostenes für den Gast-Beitrag.














