126. Batch: Wörter eines Satzes in Variablen zerlegen

Einleitung

Die vierte Abhandlung über künstliche Intelligenz steht kurz bevor und wird ein absoluter Hammer. Das ganze wird in die Desktopsearchmaschine Merlin vom Sternenhimmelstuermer integriert und ermöglicht interaktive Abfragen aus Tabellen auf Ihrem PC. Ihre Exceltabellen werden dabei zu "Think-tables" für die Antworten. Für den Sternenhimmelstuermer ist das psychologisch gesehen ein Assoziationsspiel - Freud wäre gleichermaßen wie C. G. Jung darüber erfreut, nur das der Assotiationsbegriff von Kirchturm bei einem ein Phallussymbol und beim anderen ein Symbol für religiöse Erleuchtung wäre -:) - eben genauso unterschiedlich wie die Tabellen auf ihrem PC, die Grundlage für die Antworten auf Fragen sein wird.  

Der Weg dahin ist steinig und es springen ein paar kleinere Abhandlungen heraus, die spezifische Probleme antreffen, die Sie als Batchschreiber verwenden können.

Diesmal lautete die Problemstellung: Wie mache ich in  einem Satz aus einem Textdokument oder csv jedes Wort zu einer Variable, mit der ich dann weiterarbeiten kann? Da dieses Problem im Internet weit verbreitet ist und die Antworten eher zu kompliziert sind, mal ein paar Gedanken, die der Sternenhimmelstuermer im Netz hinterlegt.

Wir bauen die die zwei Batches und einen Probetext auf. Am Ende der Abhandlung steht der Quellcode der Hauptbatch: Deutsches Problem: ß,ä ü usw. funktioniert noch nicht. Also ziemlich "englisch" . Dann wird nur ein Ergebnis angezeigt. Das wird später in Merlin abgefangen durch Visual Basic Script. Diese Abhandlung betrifft Batches - und da gibt es Probleme, die nur mit viel Aufwand gelöst werden können...Warum schwer, wenn ein anderer Lösungsweg bereits besteht?

Inhaltsangabe
Quellcode
Erklärung Schritt für Schritt
Fazit

Wir fertigen dazu eine kleine Batch und ein Textdokument und hangeln uns dann langsam zum Ergebnis durch:
Hier der komplette Quellcode:

Probe.Batch (Die Batch muss im Pfad C:\probe\search\abhandlung liegen)

set /p suche= Geben Sie den Namen des Wertes und den Titel mit Doppelpunkt getrennt ein!
Echo %suche% >such.txt
FOR /F "tokens=1,2* delims=:" %%i IN (such.txt) DO echo %%i >wert.txt
FOR /F "tokens=1,2* delims=:" %%i IN (such.txt) DO echo %%j >titel.txt
FOR /F "tokens=1,2,3* delims="  %%i  IN  ('dir C:\probe\search\abhandlung\*.txt /b /a-d') do call bereinigung.bat %%~ni
SET /p var1=<probe.log
For %%i in (%VAR1%) Do vo >>gut.log &>>C:\probe\search\abhandlung\gut.log Echo %%i
FOR /F "tokens=*" %%A IN ('findstr /N .* "gut.log"') DO echo %%A>> zahl.log
FOR /F "tokens=1,2* delims=: " %%i IN (zahl.log) DO echo %%j %%k >1.%%i.log
FOR /F "tokens=1,2* delims=: " %%i IN (such.txt) DO findstr /r /i /c:"%%j" C:\probe\search\abhandlung\1.*.log>>ergebnis.txt
FOR /F "tokens=1,2* delims=." %%i IN (ergebnis.txt) DO echo %%j >ergebnis_zahl.txt
del 1.*.log
del ergebnis.txt
del gut.log
del such.log
del titel.log
del wert.log
del zahl.log
FOR /F %%i IN (wert.txt) DO findstr /r /i /c:"%%i" C:\probe\search\abhandlung\probe.txt >>vor.txt
FOR /F "tokens=1,2,3* delims="  %%i  IN  ('dir C:\probe\search\abhandlung\vor.txt /b /a-d') do call bereinigung.bat %%~ni
SET /p var2=<vor.log
For %%i in (%VAR2%) Do vo >>vor1.log &>>C:\probe\search\abhandlung\vor1.log Echo %%i
FOR /F "tokens=*" %%A IN ('findstr /N .* "vor1.log"') DO echo %%A>> zahl.log
FOR /F "tokens=1,2* delims=: " %%i IN (zahl.log) DO echo %%j %%k >1.%%i.log
for /f %%i in (ergebnis_zahl.txt) do if exist 1.%%i.log copy 1.%%i.log endergebnis.txt
del ergebnis_zahl.txt
del 1.*.log
del such.txt
del titel.txt
del vor.log
del vor.txt
del wert.txt
del zahl.log

Dazu kommt eine bereinigung.bat. Die Datei muss im Pfad C:\probe\search\abhandlung liegen, wie die Batch.

bereinigung.bat (Der Name ist Pflicht!)

@echo off
setlocal enabledelayedexpansion
set "filename=C:\probe\search\abhandlung\%1.txt"
set "tempfile=C:\probe\search\abhandlung\%1.log"
for /F "delims=" %%a in (%filename%) do (
set text=%%a

set text=!text: =_!
echo.!text!>>%tempfile%
)


Dazu fertigen wir uns erstmal eine kleine Probetabelle (probe.txt) mit einer Überschriftszeile und einer Datenzeile an (zur Demo reicht das hier total aus, die Zeilenanzahl kann beliebig erweitert werden und der Tabellenname kann später durch variablen ersetzt werden, um später alle Tabellen auf dem PC zu durchsuchen:

probe.txt

Nachname,Straße,Nummer,PLZ,Ort Stadt
Meyer,Fantasiestr.,666,166666,Berlin

Die Datei muss im Pfad C:\probe\search\abhandlung liegen, wie die Batch: auch das wird später abgeändert. Später wird die Sucheingabe nach Straße wegen des "ß" nicht funktionieren.
Ansonsten ist die Länge und Breite der Tabelle egal und das ist das geniale für Profis. Kein %%i - %%z im For-Befehl!


Erklärung Schritt für Schritt

Die erste Zeile ist ein wenig tückisch, denn Sie beinhaltet als Separator außer Kommata noch ein Leerzeichen.

Nehmen wir an, Sie wollen,  von Herrn Meyern  nun  wissen, aus welchen Ort bzw welcher Stadt er kommt. Sie übergeben der Batch also zwei Angaben (Nachname: Meyer und Ort Stadt) und wollen nun eine Antwort [Berlin].
Dazu müssen Sie die Batch dazu bringen, in der Spalte Ort Stadt in der Zeile von Herrn Meyer nachzuschauen. Die Batch weiß natürlich nicht, an welcher Stelle die Überschrift Ort Stadt ist - das muss also ermittelt werden:

Wir improvisieren erstmal in den ersten zwei Zeilen die Eingabe eines Users. Die Datei muss im Pfad C:\probe\search\abhandlung liegen,  auch das wird später abgeändert.. Der Name: egal.bat.

01 set /p suche= Geben Sie den Namen des Wertes und den Titel mit Doppelpunkt getrennt ein!

Dann haben wir in unserem Beispiel nach Eingabe des Users der Suchbegriffe Meyer:Ort Stadt  in der Variable Suche

Die Schreiben wir nun erstmal in ein Textdokument, um nicht den Faden zu verlieren:

02 Echo %suche% >such.txt

Dann separieren wir anhand des Doppelpunktes die beiden Begriffe in verschiedene Dokumente:

03 FOR /F "tokens=1,2* delims=: " %%i IN (such.txt) DO echo %%i >wert.txt
04 FOR /F "tokens=1,2* delims=: " %%i IN (such.txt) DO echo %%j >titel.txt

Im wert.txt steht die Variable %%i (Beispiel: Meyer) und in titel.txt %%j (Beispiel: Ort Stadt)

So, jetzt machen wir erstmal einen kleinen Kunstgriff und werden in allenTextdokumenten alle Leerzeichen durch Unterstriche ersetzen. Warum? Der folgende Befel trennt dann jedes Wort in einer Zeile  - da gibt es leider ein Problem -  Separatoren  spielen bei der  Zerlegung keine Rolle, dass heißt, wir würden in der Titelzeile durch das Leerzeichen mehr Wörter als ursprünglich Spalten haben...vertrauen Sie mir und folgen den Ausführungen Sie werden es bald verstehen:

05  FOR /F "tokens=1,2,3* delims="  %%i  IN  ('dir C:\probe\search\abhandlung\*.txt /b /a-d') do call bereinigung.bat %%~ni

Wir rufen für die Bereinigung nochmal eine Batch auf, der die  Dateinamen aller  Textdokumente übergeben werden. Die Bereinigung findet in der nun folgenden bereinigung.bat statt.  Die Datei muss im Pfad C:\probe\search\abhandlung liegen, wie die Batch: auch das wird später abgeändert. Die Batch sollten Sie bereits erstellt haben, aber zur Erinnerung:

@echo off
setlocal enabledelayedexpansion
set "filename=C:\probe\search\abhandlung\%1.txt"
set "tempfile=C:\probe\search\abhandlung\%1.log"
for /F "delims=" %%a in (%filename%) do (
set text=%%a
set text=!text: =_!
echo.!text!>>%tempfile%
)

Der übergebene Name der Dokumente wird jetzt zur Weiterbearbeitung an die Batch übergeben: aus %%~ni  (Dateiname ) der Hauptbatch wird jetzt 1%. Interessant wird jetzt der For Befehl for /F "delims=" %%a in (%filename%) do. Bis dahin dürfte alles klar sein. In der Datei gibt es Textzeilen %%a (Verdopplung der Prozentzeichen durch Batch). Die werden in der Variable text (set text=%%a ) kurzfristig gespeichert. Im Text gilt die Regel (set text=!text: =_!) : ein Leerzeichen ist gleich einem Unterstrich. Danach wird der ganze Text  in einer neuen Datei ausgegeben. Wichtig ist die Zeile echo.!text!>>%tempfile%  Durch den Punkt nach dem Echo wird in der zweiten Zeile ein lästiges echo off als Warnmeldung unterdrückt

Hinweis für Google: Dieses ist die Lösung auf die Frage: Wie ersetze ich Leerzeichen in einem beliebigen Textdokument (*.txt, *.csv) durch  Unterstriche oder ein beliebiges anderes Zeichen - einfach erklärt-:)


So, dann können Sie wieder zur Hauptbatch zur Zeile 06 wechseln. Die erste Zeile eines Think-Tables oder einer guten Tabelle sollte die Überschrift sein. Die ziehen wir uns erstmal aus unserem bereinigten probe.log mit dem Befehl

06 SET /p var1=<probe.log

Richtig,  Sie lesen die erste Zeile durch diesen Befehl ein. Die anderen Zeilen dahinter werden ignoriert.  Da wir nur die Titelzeile haben wollen, ein Vorteil! In der Variablen var1 wird der Text gespeichert.

07 For %%i in (%VAR1%) Do vo >>gut.log &>>C:\probe\search\abhandlung\gut.log Echo %%i

Der übergebene Name der Dokumente wird jetzt zur Weiterbearbeitung an die Batch übergeben: aus %%~ni  (Dateiname ) der Hauptbatch wird jetzt 1%. Interessant wird jetzt der For Befehl for /F "delims=" %%a in (%filename%) do. Bis dahin dürfte alles klar sein. In der Datei gibt es Textzeilen %%a (Verdopplung der Prozentzeichen durch Batch). Die werden in der Variable text (set text=%%a ) kurzfristig gespeichert. Im Text gilt die Regel (set text=!text: =_!) : ein Leerzeichen ist gleich einem Unterstrich. Danach wird der ganze Text  in einer neuen Datei ausgegeben gut.log. Das Do vo ist ein Dummysatz. Wichtig ist der Eintrag der nächsten Zeilen mit doppelten Ausgabezeichen &>>C:\probe\search\abhandlung\gut.log Echo der Variablen %%i, also Wörter des Satzes der Variablen %VAR1%.

Das ist die Zeile, die zur Beantortung der Frage: Wie zerlege ich Wörter eines Satzes (innerhalb einer Variablen) in einzelne Wörter. Für jedes Wort %%i in der Variablen wird im Dokument gut ein Wort ausgegeben. Das sieht in unserem Beispiel so aus (Inhalt von gut.log):

Nachname
Straße
Nummer
PLZ
Ort_Stadt

Die letzte Zeile ist unsere bereinigte Ort mit Leerzeichen Stadt. Sie sehen, der Unterstrich lässt das als ein Wort interpretieren....


08 FOR /F "tokens=*" %%A IN ('findstr /N .* "gut.log"') DO echo %%A>> zahl.log

Wir numerieren ('findstr /N) jetzt die Zeilen aus dem gut.log. Das ist nichts besonders, also 1:Nachname, 2: Straße....

und schreiben eine Zeile, um aus jeder Zeilennummer eine Datei eines Wortes der Überschrift zu generieren:


09 FOR /F "tokens=1,2* delims=: " %%i IN (zahl.log) DO echo %%j %%k >1.%%i.log

Zwischenergebnis: Die Überschriften der Spalten wurde in einzelne durchnummerierte  Spalten zerlegt.  Ziel des Endergebnisses: Wir wollen  von der Überschrift Stadt_Ort die zugehörige  untere Zeile, die Herrn Meyer entspricht.
Die Batch weiß immer noch nicht, in welcher Datei 1.%%i.log sich Ort_Stadt befindet.

10 FOR /F "tokens=1,2* delims=: " %%i IN (such.txt) DO findstr /r /i /c:"%%j" C:\probe\search\abhandlung\1.*.log>>ergebnis.txt

Deshalb Schummeln wir nun ein wenig und Suchen uns aus dem Dokumentenwahnsinn das passende Dokument such.txt.
In dem steht mit einem Doppepunkt getrennt die Eingabe des Users. Da extrahieren wir den ersten Teil des Suchwortes nach dem Doppelpunkt, denn delims=: "  ist nicht gleich delims=:" . Das Leerzeichen nach dem Doppelpunkt  wird als Separator interpretiert, so dass nur das Wort Ort und nicht etwa Ort Stadt als Suchwort benutzt wird.

 Einschub: an dieser Stelle kommt ein spezielles Problem: Der For-Befehl schickt den Befehl findstr. in den DOS-Modus ü,ß usw werden nicht mehr richtig interpretiert. Leider klappt auch nicht das Ganze mit dem titel.log, da die Trenner der Hilfsdokumente oder die einfachen Leerzeichen am Ende der Textdokumente eine Suche verhindern. Bei Suchbegriffen wie Meyer, in denen kein ß steht, kein Problem..., aber ein funtkionierender Workaround ist unverhältnismäßig in einer Zwischenabhandlung - mit der Suchmaschine wird dieses Problem mit VBS gelöst...

Mit dem Befehl findstr /r /i /c:"%%j" C:\probe\search\abhandlung\1.*.log werden dann die einzelnen Zahllogs nach  dem Wort "Ort" durchsucht und das Ergebnis in der Form:  C:\probe\search\abhandlung\1.5.log:Ort_Stadt_  in unserem Beispiel ausgeworfen.

Jetzt wird es einfach:

11 FOR /F "tokens=1,2* delims=." %%i IN (ergebnis.txt) DO echo %%j >ergebnis_zahl.txt

Das Ergebnis ist hier 5, weil  wir aus der o. a. roten Zeile die 5 extrahiert haben. Als Trenner haben wir einfach einen Punkt verwendet delims=." , um dann den Inhalt zwischen zweiten und dritten Punkt zu extrahieren. In einem Dateipfad befindet sich niemals ein Punkt, also muss %%j auf jedem Fall unsere gesuchte Zahl sein - Danach kommt ein Punkt für die Dateiendung. Dahinter könnten noch tausend andere Punkte stehen - interessiert uns nicht...

Ist zur Erlangung einer Zahl so ein Aufwand angemessen? Ja, denn egal wieviele Spalten unsere Tabelle hat, mit diesem Weg bekommen wir heraus, in welcher Spalte sich der Text befindet. Das umgeht eine Prüfung nach %%a %%b usw. mit einer For-Schleife - Profis verstehen mich, dieSpaltenzahl kann so lang sein, wie es  die cmd erlaubt -:)

Jetzt müssen wir nur noch den fünften Wert in der Zeile von Herrn Meyer finden, um  unser Endergebnis zu bekommen. Erstmal werden die alten Hilfsdateien entmüllt:

12 del 1.*.log
13 del ergebnis.txt
14 del gut.log
15 del such.log
16 del titel.log
17 del wert.log
18 del zahl.log

Dazu machen wir erstmal eine Suche mit findstr  nach dem Suchwort im Beispiel Meyer. Davon gibt es im Leben und Ihren Tabellen wahrscheinlich mehrere. Das soll erstmal egal sein. Später kann man das durch eine Schleife korregieren, die die Zeilen einzeln abarbeitet. Im Augenblick gilt die Devise des Highländers: Es kann nur einen (Ergebnistext) geben.

19   FOR /F %%i IN (wert.txt) DO findstr /r /i /c:"%%i" C:\probe\search\abhandlung\probe.txt >>vor.txt

So, nun haben wir uns  gleich aus wert.txt das Suchwort - im Beispiel Meyer - herausgeholt, in dem probe.txt verglichen und die Ergebniszeile im  vor.txt gespeichert. Also haben wir im Beispiel die Zeile Meyer,Fantasiestr.,666,166666,Berlin da stehen.

Einschub: wieder dasselbe Problem mit ü ß ä ö....


Die 5 ist unser gesuchtes Wort, wenn das die dumme Batch auch wüßte, wäre alles gut...
Deshalb müssen wir wieder das Prozedere wiederholen. Da könnten ja wieder doppelte Wörter zwischen den Seperatoren stehen...

Also erstmal wieder die Prüfung, ob da Leerzeichen zwischen den Separatoren Kommata sind:

20: FOR /F "tokens=1,2,3* delims="  %%i  IN  ('dir C:\probe\search\abhandlung\vor.txt /b /a-d') do call bereinigung.bat %%~ni

Die Zeile wurde schon in Zeile 6 erklärt. Natürlich "riskieren wir bei dieser Vorgehensweise, dass der User später bei zwei Werten zwischen einem Komma, statt einem Leerzeichen zwei Werte mit Unterstrich dazwischen angezeigt bekommt - dass ist aber ziemlich egal...
Die Bereinigung.bat liefert uns nun das bereinigte Dokument vor.log, wo wieder Leerstellen gegen Unterstriche ausgetauscht werden. Das ist in unserer Probetabelle nicht der Fall, aber Sie können ja auch jede andere Tabelle in probe.txt verwenden...

21:  SET /p var2=<vor.log

Der Wert wird also wieder zur Variablen...

22: For %%i in (%VAR2%) Do vo >>vor1.log &>>C:\probe\search\abhandlung\vor1.log Echo %%i

Die Variable wieder in einzelne Wörter %%i pro Zeile zerlegt...

23: FOR /F "tokens=*" %%A IN ('findstr /N .* "vor1.log"') DO echo %%A>> zahl.log

Den Zeilen Nummern verpasst...

24: FOR /F "tokens=1,2* delims=: " %%i IN (zahl.log) DO echo %%j %%k >1.%%i.log

Die Nummern zu einzelnen Dateien mit Zahlüberschriften...%%j und %%k ist syntaktisch richtig, bei mehr als zwei Wörtern als Wert wird es eng, aber da durch Unterstriche das eigentlich ausgeschlossen ist, kein Problem...

25 for /f %%i in (ergebnis_zahl.txt) do if exist 1.%%i.log copy 1.%%i.log endergebnis.txt

und jetzt ein Endergebnis kreiert, da wir nun alle Werte für einen Abgleich haben! In ergebnis_zahl.txt steht ja unsere 5 für die Position des Wortes. Also muß  in  der unteren Spalte  das Ergebnis im mühsam erarbeiteten  1.5.log  stehen.

Die Antwort ist Berlin.

Mit:

26: del ergebnis_zahl.txt
27: del 1.*.log
28: del such.txt
29: del titel.txt
30: del vor.log
31: del vor.txt
32: del wert.txt
33: del zahl.log

Wird die Batch bereinigt.

Anmerkung: Sie können nun beliebig einen Wert und einen Titel eingeben - bis auf Straße - das ist verboten wie ä, ü...
Sie könnten im probe.txt auch eine Tabelle mit den Titeln Englisch und Deutsch erstellen und ein englisches oder Deutsches Wort suchen mit den Eingabeparametern good:Deutsch oder gut:Englisch würde Ihnen dann die Übersetzung geliefert werden - insoweit sich unter den Spaltenüberschriften Deutsch gut und Englisch good befindet.

Die Suchmaschine des Sternenhimmelstuermers wird diese Batch in der nächsten Version in abgewandelter Form beinhalten - eine Smartsuche in Think-tables, die sich aus Exeltabellen generiert - ziemlich einmalig im Internet. Die noch vorhandenen Fehler sind dann durch die Implementierung der Batch in den VBS-Code automatisch behoben, weshalb der Sternenhimmelstuermer auf eine Verbesserung dieser Batch verzichtet.

Fazit

Fazit: Mit einer Subsprache (DOS) allein, kommt man nicht ganz so weit: In der Kombination mit VBS ist die CMD eine ernst zu nehmende Alternative zu den regulären Sprache. Anhand dieser Demo ist auch zu sehen, dass passive KI durchaus emulierbar ist. Der Inhalt jeder Exceltabelle ihres PC`s kann blitzschnell  Bestandteil eines Assoziationsspiels werden.

Der Sternenhimmelstuermer ist bereits in Gedanken bei der Abhandlung Ki6.  Seine Fähigkeiten reichen leider im PC-Bereich nur für grundlegende Gedanken - die reichen aber um die KI-Forschung auf niedrigem Niveau voranzutreiben...Lernen und das Wissen zielgerichtet in Antworten anzuwenden ist dabei ein wichtiger Bestandteil - und Suchmaschinen wie Google könnten auf die Dauer ein wesentlicher Bestandeil der ersten richtigen KI werden...hoffentlich schneller als die anderen Suchmaschinen.. 




Impressum
Datenschutz