marlasdad
Goto Top

Per Batch zeilenweise Zeichen Zählen

Hallo zusammen,

ich habe mich schon doof gegoogled und brauche mal Eure Hilfe.
Also, ich möchte eine Batch-Datei schreiben, welche in einer ASC-Datei die Anzahl eines bestimmten Zeichens ';' pro Zeile zählt und mir die Zeile(n) ausgibt, wo das Zeichen mehr als x mal vorkommt.
Habe leider nichts für mich verständliches zum Thema "delims" und for... und zu dem Gesamtproblem gefunden.

Mit -> findstr /n /b /R ";" Test.txt kann ich immerhin schonmal die Semikolons rauslesen. Aber wie zähle ich die im Batch Zeilenweise und gebe Sie dann Anzahl-abhängig aus?
Kann mir jemand helfen und vielleicht auch mal die ominöse Syntax von delims erklären?

Tausend Dank schonmal!

Gruss
Ralf

Content-Key: 103571

Url: https://administrator.de/contentid/103571

Printed on: April 19, 2024 at 18:04 o'clock

Member: bastla
bastla Dec 08, 2008 at 16:54:04 (UTC)
Goto Top
Hallo marlasdad und willkommen im Forum!

Vielleicht holst Du etwas weiter aus und beschreibst eine solche Zeile näher (bzw postest ein Beispiel) - aufgrund Deines "findstr"-Ansatzes müsste ja das erste ";" bereits am Anfang stehen ...

Was soll denn in weiterer Folge mit den gefundenen Daten geschehen?

Und noch eine Frage: Da sich Batch nur bedingt zum Handling von einzelnen Zeichen eignet: Gibt es einen Einwand Deinerseits gegen die Verwendung von VBScript (vorzugsweise in einen Batch eingebettet)?

Grüße
bastla
Member: miniversum
miniversum Dec 08, 2008 at 19:03:42 (UTC)
Goto Top
Mal so ins Blaue mit den Infos bis jetzt könnte sowas gehen:
@echo off
FOR /F "tokens=1* delims=:" %%i in ('findstr /n /R ".*" "Datei.txt"') do call:search "%%j" %%i  
goto:eof

:search

if "%~1" equ "" (  
echo 0
goto:eof
)

set "line=%~1"  
set /a i=0
set /a anzahl=0

:loop
set "z="  
call set z=%%line:~%i%,1%%

if "%z%" equ "" (  
echo %anzahl%
goto:eof
)

if "%z%" equ ";" set /a anzahl=%anzahl%+1  

set /a i=%i%+1
goto:loop
Sonderzeichen machen da aber Probleme
Member: bastla
bastla Dec 08, 2008 at 19:41:16 (UTC)
Goto Top
@miniversum

Ins Blaue kann ich auch: face-wink
@echo off & setlocal
set "Datei=D:\Datei.txt"  
set "Suche=;"  
set /a Anz=3

set G=%temp%\GNO.vbs
>%G% echo Set rE=New RegExp:rE.Pattern="%Suche%":rE.Global=True:WScript.Echo rE.Execute(WScript.Arguments(0)).Count  

for /f "tokens=1* delims=:" %%i in ('findstr /n "%Suche%" "%Datei%"') do  (  
    for /f %%a in ('cscript //nologo %G% "%%j"') do (  
        if %%a gtr %Anz% echo %%j
    )
)
Ausgegeben werden alle Zeilen, in denen mehr als 3 ";" enthalten sind.

Grüße
bastla
Member: marlasdad
marlasdad Dec 09, 2008 at 07:20:16 (UTC)
Goto Top
Hallo und danke für die schnellen Antworten!

Also, ich muss Massendaten in eine Oracle-DB einlesen. Die einzelnen Werte sind durch ";" getrennt und manchmal passiert es, dass in einem Wert nochmal ein Semikolon ist. Pro Zeile sollten 20 Semikolons vorhanden sein (21Werte). Nun wäre es schön,
wenn ich so eine falschen Datensatz vor demeinlesen erkennen könnte. Das einlesen mach ich per Batch und sqlloader. Hier könnte ich ja die Prüfung einbauen.
Allerding wäre natürlich VBS auch ok. DDas könnte ich ja dann aufrufen. Wi gesagt, ich habe nichts wirklich einleuchtendes zur Erklärung von delims gefunden und würde mich über Infos hierzu freuen.

Danke und Gruss
Ralf
Member: bastla
bastla Dec 09, 2008 at 07:57:08 (UTC)
Goto Top
Hallo marlasdad!

Allerding wäre natürlich VBS auch ok. DDas könnte ich ja dann aufrufen.
Ein (zusätzliches) VBScript ist gar nicht nötig - der Batch erstellt für die benötigte Funktionalität das Script selbst (siehe mein Ansatz oben).
Kurz zu "delims": Damit werden in einer "for /f"-Schleife das/die Trennzeichen festgelegt. Anhand dieser Trennzeichen erfolgt die Aufteilung der jeweils zu bearbeitenden Zeile - vergleichbar mit der "Split"-Funktion in VB. Das Ergebnis steht dann in alphabetisch benannten Variablen (frei wählbar, meist wird mit %%i begonnen) zur Verfügung. Wird "delims" nicht angegegen, gelten Leerzeichen und TAB als Trennzeichen. Es können auch mehrere Trennzeichen festgelegt werden (etwa "delims=.:", um einen Timestamp aufzusplitten). Ein explizites "delims=" (also ohne Angabe eines Trennzeichens) sorgt dafür, dass die Zeile ungetrennt in der Variablen zur Verfügung steht.

Mit der Angabe von "tokens" steuerst Du, welche Bestandteile der Zeile verwendet werden sollen - Beispiel:
for /f "tokens=1-3,6 delims=," %%i in (D:\EineTextdatei.txt) do echo %%i-%%j-%%k-%%l
würde aus einer CSV-Datei (tatsächlich mit Komma getrennt face-wink) die Felder 1 bis 3 und 6, durch "-" verbunden, ausgeben. Eine oft nützliche weitere Schreibweise für "tokens" ist
for /f "tokens=1,3,5* delims=," %%i in (D:\EineTextdatei.txt) do echo %%i-%%j-%%k-%%l
Hier würden die Felder 1, 3, 5 sowie alle Felder ab 6 (letztere inklusive der Trennzeichen dazwischen) ausgegeben.

Um Deine Zeilen (Datensätze) aufzuteilen, müsstest Du also etwa so vorgehen (Beginn mit %%a, damit alle 21 Felder "Platz" haben):
for /f "tokens=1-21 delims=;" %%a in (D:\DeineDatei.txt) do echo %%a_%%b_..._%%u
Noch ein Hinweis: Die Schreibweise aller Beispiele mit 2 Prozentzeichen ist für die Verwendung in einem Batch gedacht - wenn Du an der Kommandozeile testen willst, jeweils nur ein Prozentzeichen verwenden.

Grüße
bastla
Member: marlasdad
marlasdad Dec 09, 2008 at 08:34:13 (UTC)
Goto Top
Super, sehr schön erklärt, Danke!

Ich habe mal beide Scripte laufen lassen.
Das erste macht wohl ne Endlosschleife und das zweite läuft soweit
Nur bei 1Million DS läuft es schon twas länger., jetzt schon 1 Stunde. Kann das?
Und was macht das gno.vbs?
Dazu habe ich nix gefunden.


gruss
marlasdad
Member: bastla
bastla Dec 09, 2008 at 09:32:02 (UTC)
Goto Top
Hallo marlasdad!

Und was macht das gno.vbs?
Das in Zeile 7 durch den Batch erzeugte Script sieht (etwas aufgeteilt) so aus:
Set rE=New RegExp
rE.Pattern="%Suche%"  
rE.Global=True
WScript.Echo rE.Execute(WScript.Arguments(0)).Count
Durch den Batch wird der Suchbegriff %Suche% (in diesem Fall ";") unmittelbar in den Scriptcode geschrieben. Das Script wird für jede Zeile der Textdatei (diese wird als Parameter übergeben) aufgerufen (was natürlich für eine große Zahl an Datensätezn entsprechend dauert) und liefert die Anzahl der enthaltenen Trennzeichen als Ausgabe an den Batch zurück.
Eine "VBS-only"-Variante sollte natürlich schneller sein:
Set rE = New RegExp
rE.Pattern = ";" 'Suchbegriff  
rE.Global = True
Anzahl = 20 'Anzahl der Suchbegriffe, die nicht überschritten werden soll  

Set fso = CreateObject("Scripting.FileSystemObject")  
DateiEin = WScript.Arguments(0)
DateiAus = fso.GetParentFolderName(DateiEin) & "\" & _  
    fso.GetBaseName(DateiEin) & "-Fehler" & "." & _  
    fso.GetExtensionName(DateiEin)

Set Ein = fso.OpenTextFile(DateiEin)
Set Aus = fso.CreateTextFile(DateiAus, True)
i = 1
Do While Not Ein.AtEndOfStream
    Zeile = Ein.ReadLine
    If rE.Execute(Zeile).Count > Anzahl Then
        Aus.WriteLine Right(Space(8) & i, 8) & ": " & Zeile  
    End If
    i = i + 1
Loop
Aus.Close
Ein.Close
Zu starten wäre das Script mit Übergabe der zu untersuchenden Datei, also etwa:
cscript //nologo CheckData.vbs "D:\Datei.txt"
In dieser Fassung des Scripts erfolgt keine Prüfung auf Vorhandensein der Eingabedatei (kann aber schon im aufrufenden Batch erledigt werden). Die fehlerhaften Dateien werden (inkl max 8-stelliger Zeilennummern, rechtsbündig formatiert) in eine Datei im gleichen Pfad wie die übergebene Datei mit dem Namenszusatz "-Fehler" geschrieben.

Grüße
bastla
Member: marlasdad
marlasdad Dec 09, 2008 at 10:10:00 (UTC)
Goto Top
Das ist ja ein riesen Unterschied von der Laufzeit her!
Das VBS läuft super!
Danke!!