/* Anwendung: Tokenizer H.Leiss, CIS 1. Lies Zeichenweise von einer Datei (oder der Konsole), 2. Zerlege die Zeichenfolge in einzelne W"orter (Token), 3. Wandle die W"orter in Prolog-Atome um, 4. Erkenne das Satzende, und 5. Gib den n"achsten Satz als Atomfolge aus. */ /* Einlesen von S"atzen aus einer Datei */ read_sentence(File,Atomlist) :- % Fall 1: File ist offen current_stream(File,read,Stream),!, read_sentence(Stream,Sentence,[]), stringToAtoms(Sentence,Atomlist). read_sentence(File,Atomlist) :- % Fall 2: sonst open(File,read,Stream), read_sentence(Stream,Sentence,[]), stringToAtoms(Sentence,Atomlist). /* Alternativ: Einlesen von der Konsole */ eingabe :- write(user,'Beende die Eingabe mit <.|?>'), nl,read_sentence(user,Sentence,[]), stringToAtoms(Sentence,Atomlist), nl,writeq(Atomlist). /* Bis zum Satzende vom Strom lesen */ read_sentence(Stream,Sentence,Seen) :- get0(Stream,Char),!, read_sentence(Stream,Sentence,Char,Seen). % read_sentence(+Strom,-Sent.,-LastChar,-CharsRev) read_sentence(Stream,Sentence,Char,Seen) :- dateiende(Char), !, reverse(Seen,Sentence), name(Atom,Sentence), nl,write(Atom),nl, close(Stream),nl, write('End of File reached; Stream closed.'). read_sentence(Stream,Sent,Char,[Pkt,Zif|Seen]) :- ordinalzahlende([Zif,Pkt,Char]), !, read_sentence(Stream,Sent,[Char,Pkt,Zif|Seen]). read_sentence(Stream,Sent,Char,[R|Seen]) :- abkuerzungsendeRev(Char,[R|Seen]), !, read_sentence(Stream,Sent,[Char,R|Seen]). read_sentence(Stream,Sentence,Char,[C|Seen]) :- satzende([C,Char]), % Satzende gefunden, Satz ausgeben: !, reverse([C|Seen],Sentence). read_sentence(Stream,Sentence,Char,Seen) :- read_sentence(Stream,Sentence,[Char|Seen]). /* Tokenizer: Zeichenreihe -> Atomfolge Vorgehensweise: 1. durchlaufe die Zeichenfolge von links nach rechts, 2. unterscheide dabei zwei F"alle: a. das n"achste Zeichen beginnt ein Wort (nt) b. das n"achste Zeichen setzt ein Wort fort (at) 3. stapele die schon erkannten W"orter (als Atome), 4. am Ende gib den umgekehrten Stapel aus. */ /* stringToAtoms(String,Atomlist) */ stringToAtoms(String,Atomlist) :- tokenize(String,nt,[],Atomlist). /* (a) tokenize(+String,nt,+TokensRev,-Atoms) */ tokenize([T|String],nt,Rs,Ts) :- (leerZeichen(T); zeilenende(T)), % fuehrende Leerzeichen,Zeilenumbruch weg !,tokenize(String,nt,Rs,Ts). tokenize([T|String],nt,Rs,Ts) :- sonderzeichen(Atom,T), % eigenes Token !,tokenize(String,nt,[Atom|Rs],Ts). tokenize([C|String],nt,Rs,Ts) :- !,tokenize(String,at,[[C]|Rs],Ts). /* Tokenizer bei Worttrennung, Zeilenende, Leerzeichen */ /* (b) tokenize(+String,at,+TokensRev,-Atoms) */ % Fall at = das letzte Char lag in einem Token tokenize([N,L|String],at,[[T|Cs]|Rs],Ts) :- worttrennung([T,N]),leerZeichen(L), % Leerzeichen am Zeilenanfang beseitigen: !, tokenize([N|String],at,[[T|Cs]|Rs],Ts). tokenize([N|String],at,[[T|Cs]|Rs],Ts) :- worttrennung([T,N]), % Trennzeichen und Umbruch beseitigen: !, tokenize(String,at,[Cs|Rs],Ts). tokenize([T|String],at,[R|Rs],Ts) :- zeilenende(T), % Sonstige Zeilenenden sind Tokengrenzen !, tokenToAtom(R,Atom), tokenize(String,nt,[Atom|Rs],Ts). tokenize([T|String],at,[R|Rs],Ts) :- leerZeichen(T), % Sonst: Tokenende erreicht, neues anfangen !, tokenToAtom(R,Atom), tokenize(String,nt,[Atom|Rs],Ts). /* Tokenizer (in Abk"urzungen und bei Sonderzeichen) (b) tokenize(+String,at,+TokensRev,-Atoms) */ % Sonderfaelle bei Abkuerzungen tokenize([S|String],at,[R|Rs],Ts) :- punktZeichen(S), suffixAbkuerzung(Abkuerzung), % Parkstr. 45 reverse(Abkuerzung,RevAbk), append(RevAbk,_,[S|R]), !, tokenToAtom([S|R],Atom), tokenize(String,nt,[Atom|Rs],Ts). tokenize([S|String],at,[R|Rs],Ts) :- punktZeichen(S), abkuerzung(Abkuerzung), % z.T. append(Praefix,[S|Suffix],Abkuerzung), reverse(Praefix,R), append(Suffix,Rest,String), !, name(Atom,Abkuerzung), tokenize(Rest,nt,[Atom|Rs],Ts). % Sonderfall bei Sonderzeichen tokenize([S|String],at,[R|Rs],Ts) :- sonderzeichen(SAtom,S), !, tokenToAtom(R,Atom), tokenize(String,nt,[SAtom,Atom|Rs],Ts). /* Tokenizer (Token erweitern, Ende der Eingabe) (b) tokenize(+String,at,+TokensRev,-Atoms) */ tokenize([C|String],at,[R|Rs],Ts) :- % Erweitere das angefangene Token !,tokenize(String,at,[[C|R]|Rs],Ts). tokenize([],at,[R|Rs],Ts) :- tokenToAtom(R,Atom), reverse([Atom|Rs],Ts). tokenize([],nt,Rs,Ts) :- reverse(Rs,Ts). tokenToAtom(RevToken,Atom) :- reverse(RevToken,Token), name(Atom,Token). /* Hilfspr"adikate */ % Satzende, Zeilen- und Worttrennung: dateiende(-1). % eof zeilenende(10). % newline satzende(". "). % nicht: .Char satzende("? "). satzende("! "). satzende(": "). satzende(".\n"). % . newline satzende("?\n"). satzende("!\n"). satzende(":\n"). ordinalzahlende([Ziffer,Punkt,Char]) :- ziffer(Ziffer), punktZeichen(Punkt), leerZeichen(Char). ziffer(Z) :- member(Z,"0123456789"). worttrennung("-\n"). % - newline abkuerzungsendeRev(Char,[R|Seen]) :- leerZeichen(Char),punktZeichen(R), (abkuerzung(Abk); suffixAbkuerzung(Abk)), reverse(Abk,RevAbk), append(RevAbk,_,[R|Seen]). % Sonderzeichen leerZeichen(32). % name(' ',[32]) % Ausser in Zahlausdruecken und Abkuerzungen % sollten folgende Zeichen % zu eigenstaendigen Token werden: kommaZeichen(C) :- name(',',[C]). punktZeichen(C) :- name('.',[C]). sonderzeichen('.',46). % name('.',[46]). usw. sonderzeichen(',',44). sonderzeichen(';',59). sonderzeichen(':',58). sonderzeichen('!',33). sonderzeichen('?',63). sonderzeichen('"',34). % bei Zitaten sonderzeichen('(',40). sonderzeichen(')',41). % Abk"urzungen abkuerzung("Jan."). abkuerzung("Feb."). abkuerzung("Apr."). abkuerzung("Aug."). abkuerzung("Sept."). abkuerzung("Okt."). abkuerzung("Nov."). abkuerzung("Dez."). abkuerzung("Dr."). abkuerzung("Prof."). abkuerzung("Fa."). abkuerzung("Frl."). abkuerzung("bzw."). abkuerzung("etc."). abkuerzung("usw."). abkuerzung("vgl."). abkuerzung("Nr."). abkuerzung("a.a.O."). abkuerzung("s.u."). abkuerzung("m.M."). abkuerzung("z.B."). abkuerzung("z.T."). abkuerzung([C,46]) :- grossbuchstabe(C). grossbuchstabe(C) :- member(C,"ABCDEFGHIJKLMNOPQRSTUVWXYZ"). suffixAbkuerzung("str."). % ---------------- Tokenizer Ende ------------------------------