//mylaiza.java // an eliza, in java import java.awt.*; import java.io.*; import java.net.*; import java.applet.*; import java.util.*; public class mylaiza extends Applet{ /** a simple rule-based eliza clone, (cf. my lai massacre) parameter name "datafile" = filename with rules info*/ TextArea transcript; TextField inbox; String rules; matcher reply,preprocess,switchviewpoint; private String nextfileline(DataInputStream d) { /** returns next non comment in inputstream comment = starts with ; */ String line=new String(""); try { line=d.readLine(); while (line.charAt(0) ==';') line=d.readLine();} catch (Exception e) { return "END";}; //if end of file return "END" -- wouldn't you know, the docs don't explain EOF //System.out.println(line); return line;}; String getrules(DataInputStream f){ String s=new String(""); String line=new String(nextfileline(f)); while (!line.equals("END")){s=(s+line+"\n");line=nextfileline(f);}; return s;} public void init(){ //** read in rules from file, create editboxes DataInputStream f; URL f1; int i,j,cot; StringTokenizer sit; String line=""; String rules,separators,matchchars; setBackground(new Color(180,180,255)); String filename=getParameter("datafile"); try {f1=new URL(getDocumentBase(),filename); f=new DataInputStream(f1.openStream());} catch (IOException e) {System.out.println("File not available");return;} line=nextfileline(f); //input wildcard separator char (#|) matchchars=line.substring(0,1); //wildcard char # separators=line.substring(1,3)+"\n"; //separator char | //input preprocessing rules // the way this works, the last one is the destination, // convert to canonical form, correct mispellings // and all previous words get translated to the last one // this puts all the intial words to the final class rules=getrules(f); preprocess=new matcher(rules,0,separators,matchchars); //input context switch rules //two rules, from to, eg. you|me rules=getrules(f); switchviewpoint=new matcher(rules,0,separators,matchchars); //input replies rules // match the first element, with wildcards // pick a random reply, substitute wildcard match, rules=getrules(f); reply=new matcher(rules,1,separators,matchchars); transcript=new TextArea(10, 80); transcript.setEditable(false); inbox=new TextField(80); add(transcript); add(inbox); transcript.appendText("Hi. I am mylaiza.\n"); inbox.requestFocus(); matcher test=new matcher("wash=test"); d("Test"+test.match("this is a wash up")); d(test.stuff("wash","test","this is a wash up")); //d(match("test"+x,"this is a testing of match")); } public boolean keyDown(Event evt, int key) { if (key !='\n') return false; String text = inbox.getText(); processinput(text); inbox.setText(""); return true;} /* public void start(){ cotton=new Thread(this); cotton.start();} public void stop(){ cotton.stop();} */ private void processinput(String in){ String matches; String out=new String(in); //substitute i,I // for each element in the rules, // check test, pick replies, substitute matched pieces // switch view point, // print question and reply to box reply to box transcript.appendText(in+"\nMylaiza:"); out=preprocess.match(out); out=reply.match(switchviewpoint.match(out)); transcript.appendText(out);} private void d(String line){ System.out.println(line); } } //************************************ //matcher.java /**a class to do pattern matching ops: constructor(string of all rules,string of separators for rule,field,argument(s)/result(s)), int type, 1=match once 0=match many (stop at 1 replacement, dont stop) string of patten match characters for match all, match 1 word, etc. to be worked out later contructor(string of all rules); using defaults "|=\n","*?",1 meant to be a basis for further pattern match work) match(string to match) returns corresponding output an obvious subclass is a singlerule match, 1 arg string, list of results rule=1 arg string and list of result strings, or simply a list of strings could have its own class, but... ops, keyword{ longest, for hashlookup ), selector arg() pickone(), subst, matches{list of matched sections.} result, relaced into rule a rule at this point is an array of String pickone(rule), why to choose result from multiple choice it might be good for a learning procedure to override; prhaps not repeat last one for optimization: each arg of a rule has a keyword (longest), do a hashtable lookup on each word in line for keyword, then use slower more complete matcher fastmatch(String word)=check each word, return rule if applies */ class matcher { String rules[][]; //storing all rules, each array knows its length Random ran=new Random(); int stopafter;// stop after this many replacements 1 or don't stop String wildcars;// all the wildchar characters, *****2b written static String x="\033";// special code char for pattern matching public String[] parsetoarray(String rawlist,String separator){ // break the string into an array of strings, which were separated by.. StringTokenizer sit=new StringTokenizer(rawlist, separator); int c=sit.countTokens(); String[] stimpy=new String[c]; for (int i=0;i=0) //found variable match it puretext=pattern.substring(0,pip);//before the wildchar else puretext=pattern; sip =findex(puretext,source); d("matched:"+pattern+","+source+pip+","+sip); if (sip<0) return x; //not found if (pip<0) return (""); //found but no pat to return else return(source.substring(sip+puretext.length())); } boolean isnotletter(char c){ if (!( ((c >= 'A') && (c<='Z')) || ((c >= 'a') && (c<='z')) )) return true; else return false;} int findex(String pat, String line) { // would have used indexOf, but need only whole words, and case insensitive String p=pat.toLowerCase(); if (p.length()==0) return 0;//automatch String l=line.toLowerCase(); int ind; char prevc,nextc; ind=l.indexOf(p); while (ind>=0) { // check matches for whole word if (p.equals(x)) return ind; // special char prevc=((ind==0)?' ':l.charAt(ind-1)); nextc=((ind+p.length()==l.length())?' ':l.charAt(ind+p.length())); if (isnotletter(prevc) && isnotletter(nextc)){ return ind;} if (l.length()>=ind+p.length()) return -1; // at end ind=l.indexOf(p,ind+1); } return -1; }//not found public String stuff(String from, String to,String line){ //put (ie stuff) the from in place of to in the line String out=new String(line); int pip=findex(from,out); while (pip>=0) { out= out.substring(0,pip)+to+out.substring(pip+from.length()); d("stuff:"+out+","+from+","+to); pip=findex(from,out); if (stopafter==1) break;} return out;} private void d(String line){ //System.out.println(line); } }