000
10.02.2008, 10:33
the_Crow
|
Ich versuche zur Zeit eine Art Chatbot zu coden, der auf bestimmte Befehle reagiert. Im Moment ist es so, dass der Interpreter für die Befehle die komplette Eingabe, des Users bekommt und dort nach bestimmten Worten sucht. Wenn eine Wort gefunden wird, führt der Interpreter den entsprechenden Befehl aus.
<?php $q = $_GET['q'];
if(preg_match("/hello/i", $q)!=false){ header("Content-Type: text/xml",true); echo "<?xml version="1.0"?>"; echo "<response>"; echo "<request>coyote</request>"; echo "<result>OK</result>"; echo "<result-text>"; echo "Hello.<br />"; echo "</result-text>"; echo "</response>"; } elseif(preg_match("/test/i", $q)!=false){ header("Content-Type: text/xml",true); echo "<?xml version="1.0"?>"; echo "<response>"; echo "<request>test</request>"; echo "<result>OK</result>"; echo "<result-text>"; echo "test...<br />"; echo "</result-text>"; echo "</response>"; } ?>
Wenn der Input hello world ist, dann wird der Befehl hello ausgeführt. Bei hellooooo ebenso. Das ganze funktioniert wunderbar, aber es ist sehr umständlich und platzintensiv. Meine Idee wäre Befehle und Ausgaben in einem Array oder in einer MySQL-DB zu speichern. Leider erreiche ich damit nicht das selbe Ergebnis. Bei beiden Varianten müssen Eingabe und Befehl genau übereinstimmen. Beide wären aber platzsparender. Weiß jemand, wie man das machen könnte?
Falls sich jemand über if(preg_match("/hello/i", $q)!=false) wundert. Mit if(preg_match("/hello/i", $q)) funktioniert es nicht.
===========================================================
Meine zweite Frage wäre, wie man Befehle mit Parametern macht. Z.B. /setname Crow. /setname ist der Befehl und Crow ein Parameter. Der Interpreter bekommt den Input, sucht nach /setname und speichert alles nach dem ersten Leerzeichen in eine Variable. Bis jetzt hat das auch nicht so richtig funktioniert.
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
Dieser Beitrag wurde am 10.02.2008 um 10:39 von the_Crow bearbeitet.
|
|
Profil || Suche
|
001
10.02.2008, 11:04
Gravok
|
Das mit den Parametern würd ich theoretisch einfach so machen:
Erst nach /setname suchen und dann den String in nen Array splitten, und zwar so das du bei bla[0] dann /setname hast und bei bla[1] den Rest.
D.h. du machst dann limit 2, obs wirklich mit explode geht kA, von VB dachte ich jetzt auch mehr an left, mid, right um strings zu splitten, allerdings hat php nichts dergleichen...
--
23 - Nichts ist so wie es scheint
Dieser Beitrag wurde am 10.02.2008 um 11:05 von Gravok bearbeitet.
|
|
Profil || Suche
|
002
10.02.2008, 11:10
the_Crow
|
Das wäre eine Möglichkeit. Nur hätte ich dann bei Befehlen wie /setname Josef Huber Probleme.
Edit: /setname Josef Huber würde doch funktionieren. Hab das mit "limit" falsch verstanden.
Edit2: Es gibt doch Problem. preg_match("//setname/i", $q) funktioniert nicht. /setname soll gesucht werden.
Warning: preg_match() [function.preg-match]: Unknown modifier 't' in /srv/www/vhosts/the-crow.at/httpdocs/ai/coyote_1.0/cmd.php on line 169
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
Dieser Beitrag wurde am 10.02.2008 um 11:21 von the_Crow bearbeitet.
|
|
Profil || Suche
|
003
10.02.2008, 13:44
Bluthund
|
Wie wärs mit
/\/setname/i ?
Und wegen dem Rückgabewert von preg_match
http://de.php.net/preg_match : preg_match() gibt die Anzahl der Übereinstimmungen mit Suchmuster zurück. Das ist entweder 0 (keine Übereinstimmung) oder 1, weil preg_match() die Suche nach der ersten Übereinstimmung beendet. Im Gegensatz dazu setzt preg_match_all() die Suche bis zum Ende von Zeichenkette fort. preg_match() gibt FALSE zurück, falls ein Fehler auftrat. "!= false" ist semantisch also nicht das was du willst.
--
The C language combines all the power of assembly language with all the ease-of-use of assembly language. "humorig is n blödwort :>" by -CarniGGeLjumpR-
Dieser Beitrag wurde am 10.02.2008 um 14:02 von Bluthund bearbeitet.
|
|
Profil || Suche
|
004
10.02.2008, 14:15
the_Crow
|
Dankeschön. /\/setname/i funktioniert. != false werd ich zu ==1 machen. Bleibt nur noch das erste und größte Problem.
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
|
|
Profil || Suche
|
005
10.02.2008, 15:11
Bluthund
|
Meinst du damit
Meine Idee wäre Befehle und Ausgaben in einem Array oder in einer MySQL-DB zu speichern. Leider erreiche ich damit nicht das selbe Ergebnis. Bei beiden Varianten müssen Eingabe und Befehl genau übereinstimmen. Beide wären aber platzsparender. Weiß jemand, wie man das machen könnte? ? Um mal auf die von dir genannten Ansätze einzugehen: Warum baust du dir nicht ne Klasse (bzw eine Struktur, was es ja in PHP nicht gibt) mit 3 Membervars (Name, Regex, Result). Dann nen Array davon (mit so vielen Elementen wie du Befehle hast) und entsprechend deiner Befehle füllen. Dann kannst für jedes (foreach) Element des Arrays dein if-Konstrukt auf den im Array gespeicherten Regex anwenden und die Ausgabe mit dem Namen und dem Result im Array bewerkstelligen. Ansonsten wäre die Lösung mit ner DB analog dazu. Ne Table mit id, name, regex und result. Dann nen Query (SELECT * FROM foobar) und solange Ergebnisse da sind in nen Array fetchen und durch dein if jagen.
Alles in allem ist das aber relativ statisch und spätestens bei deinem setname wirst du darauf stoßen, dass du für solche Befehle mit Parametern da wieder nen extra Zweig brauchst, was dann ja auch nicht wirklich im Sinne des Erfinders wäre. Meine Idee hierzu wäre: Du erstellst eine Basisklasse Befehl, welche alle nötigen Grundeigenschaften eines Befehls enthält (zB id, name, regex, resulttext). Dazu noch eine Methode zum matchen des Regexes auf einen String und eine Methode zum verarbeiten von Parametern, eine für die Ausgabe der Standardantwort, etc. Dann leitest du davon Klassen für deine jeweiligen Befehle ab und implementierst da entsprechend des Befehls die Methoden (Parameterverarbeitung, Ausgabe, etc). Dann erstellst dir nen Array und instantiierst da für jeden Befehl ein Objekt der jeweiligen Klasse. Dann wieder mit foreach durch das Array. Statt if( preg_match(...) ) machst dann if( $array->regex_such_methode(...) ). Du kannst natürlich auch weiterhin if( preg_match(...) verwenden, aber mit ner extra Methode für die das RegexMatching kannst du die Funktionalität bei Bedarf für einzelne Tochterklassen erweitern (zB um gleich noch die Parameter zu matchen, oä). Im if rufst dann die Methode zur Parameterverarbeitung und anschließend die Ausgabe auf. Gibt evtl auch bessere Lösungen aber das ist jetz die, die mir spontan eingefallen ist, um dem Kriterium "Code kurz halten" zu genügen.
--
The C language combines all the power of assembly language with all the ease-of-use of assembly language. "humorig is n blödwort :>" by -CarniGGeLjumpR-
|
|
Profil || Suche
|
006
10.02.2008, 15:37
the_Crow
|
Das klingt nicht so schlecht, aber ich versteh nur teilweise was du meinst.
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
|
|
Profil || Suche
|
007
10.02.2008, 20:46
Bluthund
|
Wäre nicht schlecht zu wissen, was du nicht verstanden hast, um evtl näher drauf eingehen zu können, falls es irgendwie missverständlich war. Denn alles nochmal anders hinschreiben in der Hoffnung, dass es dann besser verständlich ist, ist auch nich so der Bringer.
--
The C language combines all the power of assembly language with all the ease-of-use of assembly language. "humorig is n blödwort :>" by -CarniGGeLjumpR-
|
|
Profil || Suche
|
008
10.02.2008, 21:03
the_Crow
|
Ich versteh nicht wie die Klassen und Methoden aussehen und miteinander verbunden sein sollen.
Ein Problem deiner Variante wäre, dass man keine neuen Befehle über einen anderen Befehl hinzufügen kann. zB: /addcommand [name] [output] Das würde mit einer mysql-db besser funktionieren. Hab mir auch mal ein Script gecodet, dass mit einer db arbeitet. Spezielle Befehle wie "/setname" muss ich aber noch immer direkt in den Code schreiben.
<?php $q = $_GET['q']; $ok = false;
if(preg_match("/\/start/i", $q)==1){ header("Content-Type: text/xml",true); echo "<?xml version="1.0"?>"; echo "<response>"; echo "<request>/start</request>"; echo "<result>OK</result>"; echo "<result-text>"; echo "Welcome to Coyote 1.0<br />"; echo "Type <cmd value="/help"/> for a list of special commands.<br />"; echo "</result-text>"; echo "</response>"; }else{ $result = mysql_query("SELECT * FROM cmd"); while($row = mysql_fetch_array($result)){ $cmd = str_replace("/","\/",$row['cmd']); if(preg_match("/".$cmd."/i", $q)==1){ header("Content-Type: text/xml",true); echo "<?xml version="1.0"?>"; echo "<response>"; echo "<request>".$row['cmd']."</request>"; echo "<result>OK</result>"; echo "<result-text>"; echo $row['output']."<br />"; echo "</result-text>"; echo "</response>"; $ok = true; } } if(!$ok){ echo "ERROR"; header("Content-Type: text/xml",true); echo "<?xml version="1.0"?>"; echo "<response>"; echo "<request></request>"; echo "<result>UNKNOWN_CMD</result>"; echo "<result-text>"; echo "Unknown command <cmd value="".$q."" run="0"/>. Type <cmd value="/help"/> for a list of valid commands."; echo "</result-text>"; echo "</response>"; } } ?>
Es ist auf jeden Fall platzsparender als alles in den Code zu schreiben. Jetzt müsste ich nur noch die "special Commands" vereinfachen. Das könnte ich auf deine Art machen.
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
Dieser Beitrag wurde am 10.02.2008 um 21:05 von the_Crow bearbeitet.
|
|
Profil || Suche
|
009
10.02.2008, 22:17
Bluthund
|
Hab schon lang nix mehr mit php gemacht und bevor ich mir jetzt die Syntax von Klassen in PHP5 reinziehe, hier mal bisschen Pseudocode wies gemeint war:
Klasse cmd // Basisklasse von der alles abgeleitet wird { öffentliche Methoden: Regex_Match( string ); // macht nix weiter als nen preg_match( regex, string ) in der Basisimplementation Parameter_einlesen( string ); // hier ne Konvention schaffen: ist Befehl noch vorn dran oder nicht?; in der Basisimplementation ohne Funktionalität Aktion(); // veranstalte irgendnen Pfeffer; keine Funktionalität in Basisimplementation Ausgabe(); // macht den ganzen echo-Kram
// Get und Set-Methoden für die privaten Variablen nicht vergessen
private Variablen: cmd; regex; result; }
Klasse cmdHello abgeleitet von cmd { öffentliche Methoden: cmdHello(); // Konstruktor // hier private Variablen der Basisklasse entsprechend setzen // cmd = "hello"; // regex = "/hello/i"; // result = "Hello.<br />";
// sonst keine öffentlichen Methoden, weil die Basisimplementation schon ausreichend funktional ist }
Klasse cmdSetName abgeleitet von cmd { öffentliche Methoden: cmdSetName(); // Konstruktor // hier private Variablen der Basisklasse entsprechend setzen // cmd = "setname"; // regex = "/\/setname/i"; // result = "Setname.<br />";
Parameter_einlesen( string ); // liest den Parameter in die Variable neuer_name ein Aktion(); // ändert den Namen //Ausgabe evtl überschreiben um zB neuer_name mit auszugeben
private Variablen: neuer_name; }
Ist natürlich, wie du schon richtig angemerkt hast, recht statisch. Man könnte jetz allerdings noch ne Klasse cmdSimpleCmdFromDB erstellen, welche die Methode Regex_Match überschreibt und dort vor dem eigentlichen preg_match(...) aus einer Datenbank liest, in einer Schleife alle von der DB geschickten Ergebnisse matched und entsprechende Schritte ergreift (cmd, regex, result setzen). Wobei ne DB wahrscheinlich eh Overkill ist und es ne einfache Textdatei auch tut.
--
The C language combines all the power of assembly language with all the ease-of-use of assembly language. "humorig is n blödwort :>" by -CarniGGeLjumpR-
Dieser Beitrag wurde am 10.02.2008 um 22:37 von Bluthund bearbeitet.
|
|
Profil || Suche
|
010
11.02.2008, 11:00
the_Crow
|
Jetzt ergibt das ganze einen Sinn für mich. Die db ist wirklich "Overkill". Werd das ganze mit einer Textdatei machen.
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
|
|
Profil || Suche
|
011
11.02.2008, 20:19
the_Crow
|
Alles mit Klassen zu machen ist verdammt schwer. Hab bis jetzt erst sehr wenig mit OOP gemacht.
Edit: Hab das ganze jetzt mit einer Textdatei gelöst. Ich muss mir nur noch für die Spezialbefehle eine Methode schreiben.
--
www.the-crow.at - meine persönliche Website | TibiaGerman | Twitter | Wiaschtlsiada
Dieser Beitrag wurde am 11.02.2008 um 22:04 von the_Crow bearbeitet.
|
|
Profil || Suche
|