jens-fi
Goto Top

13. Semikolon pro Zeile in Textdatei mit Leerzeichen ersetzen - geht das?

Servus zusammen.

Ich stehe vor einem kleinen Problem: Ich habe immer wieder mit CSV-Dateien zu tun, in denen die Werte mit einem Semikolon getrennt sind. Und da ich in jeder Datei in jeder Zeile das 13. Semikolon durch ein Leerzeichen ersetzen muss, um zwei Werte in ein Feld zu bekommen (genauer: Feld 13 ist der Vorname, Feld 14 der Nachname und beides soll nachher zusammen dastehen), ist das in Handarbeit echt mühsam.
Das Problem an der Sache ist, dass die absolute Position dieses 13. Semikolons nicht immer dieselbe ist. Mal sind 40 Zeichen davor, mal 140.
Der Dateiname ist immer gleich (export.csv) und soll dann in bearbeitet.csv gespeichert werden.

Da meine VBS-Kenntnisse = null sind und meine letzte Batch-Datei aus den Zeiten von Windows3.1 stammt, bin ich auf Hilfe angewisen.

Wer mag mir seine Lösungsvorschläge erläutern?


Ich müsste anschließend noch "Deutschland" mit "D" ersetzen, aber ich hoffe, das schaffe ich dann alleine.

Grüße, Jens

Content-Key: 385764

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

Printed on: April 26, 2024 at 14:04 o'clock

Member: falscher-sperrstatus
falscher-sperrstatus Sep 07, 2018 at 10:20:29 (UTC)
Goto Top
Hallo Jens,

willst du das automatisiert tun? Sonst lad es in Excel, lössche die Zeilen, exportier es als CSV. Alternativ schreibst du ein Skript trenne nach 13. ; (Regex) und pack den Teil 2 in neue Datei.

Dtld in D ist nur ne simple Search and Replace Funktion

VG
Member: Bitboy
Bitboy Sep 07, 2018 at 10:39:57 (UTC)
Goto Top
Moin,

in vbs sucht man mit der instr-Funktion die liefert immer das nächste gefundene.
Du kannst also die Funktion in einer Schleife aufrufen um immer das nächste Semikolon pro Zeile zu bekommen.

Oder du verwendet ein Array und splittest die Zeile anhand des Semikolon und baust den String danach wieder so zusammen wie du ihn brauchst.
Member: erikro
erikro Sep 07, 2018 updated at 12:12:56 (UTC)
Goto Top
Moin,

dafür würde ich mir ein Powershell-Skript schreiben. Mal schnell hingeschrieben, ohne zu testen:

$old_data = Import-Csv "export.csv" -delimiter ";" -Encoding utf8 # Die Kodierung evtl. anpassen  
foreach($dataset in $old_data) {

   $row = New-Object PSObject -Property @{
   Field1 = "$dataset.field1"  
   Field2 = "$dataset.field2" # und so weiter bis alle Felder verarbeitet wurden. Die Feldnamen musst Du natürlich anpassen.  
   fullname = "$dataset.vorname $dataset.nachname"  
   country = "D" # Sollten da auch andere stehen, dann muss da noch ein if hin.  
   }
   $row | Export-Csv "bearbeitet.csv" -Delimiter ";" -Encoding utf8 -Append  

}

hth

Erik
Member: Friemler
Solution Friemler Sep 07, 2018 updated at 13:30:38 (UTC)
Goto Top
Hallo @jens-fi,

hier noch eine kommentierte VBScript-Lösung:
'Alle Variablen müssen vor ihrer Verwendung deklariert werden  
Option Explicit


'*******************************************************************************  
'Deklaration von Konstanten  
'*******************************************************************************  

Const InFileName      = ".\Export.csv"  
Const OutFileName     = ".\Bearbeitet.csv"  

Const ForReading      = 1
Const ForWriting      = 2
Const ForAppending    = 8

Const AsSystemDefault = -2
Const AsUnicode       = -1
Const AsAnsi          = 0


'*******************************************************************************  
'Deklaration von Variablen  
'*******************************************************************************  

Dim objFSO, objInFile, objOutFile
Dim strLine, arrLine, intCnt


'*******************************************************************************  
'Hauptprogramm  
'*******************************************************************************  

'Benötigte Objekte erzeugen  
Set objFSO = CreateObject("Scripting.FileSystemObject")  

'Quell- und Zieldatei öffnen  
Set objInFile  = objFSO.OpenTextFile(InFileName, ForReading, False, AsAnsi)
Set objOutFile = objFSO.OpenTextFile(OutFileName, ForWriting, True, AsAnsi)

'Quelldatei zeilenweise einlesen, bearbeiten und in die Zieldatei schreiben  
Do While Not objInFile.AtEndOfStream
  'Zeile einlesen  
  strLine = objInFile.ReadLine

  'Zeileninhalt anhand der Semikolons zerlegen  
  arrLine = Split(strLine, ";")  
  strLine = ""  

  'Vor- und Nachname zusammenfügen  
  For intCnt = 0 To UBound(arrLine)
    If intCnt <> 13 Then
      If intCnt > 0 Then strLine = strLine & ";"  
      strLine = strLine & arrLine(intCnt)
    Else
      strLine = strLine & " " & arrLine(intCnt)  
    End If
  Next

  'Deutschland durch D ersetzen  
  strLine = Replace(strLine, "Deutschland", "D", 1, -1, vbTextCompare)  

  'Zeile in Ausgabedatei schreiben  
  objOutFile.WriteLine strLine
Loop

'Dateien schließen  
objInFile.Close
objOutFile.Close

Ich bin mal davon ausgegangen, dass die Eingabe- und Ausgabedatei die Zeichencodierung Windows-1252 bzw. ANSI haben.

Das Script funktioniert nur, wenn es in der Eingabedatei keine Felder gibt, die als Nutzdaten Semikolons enthalten.

Grüße
Friemler
Member: erikro
erikro Sep 07, 2018 at 12:16:59 (UTC)
Goto Top
Moin,

Zitat von @Friemler:
Das Script funktioniert nur, wenn es in der Eingabedatei keine Felder gibt, die als Nutzdaten Semikolons enthalten.


Deshalb würde ich das auch immer mit einer Sprache machen, die csv beherrscht. Das splitten einer csv am Trennzeichen ist einfach gefährlich. Wenn man das wirklich sicher machen will, dann muss man mit einer regex prüfen, ob es zwischen zwei Anführungszeichen steht, sofern die Daten in solche eingeschlossen sind. Wenn nicht, dann dürfen in csv die Daten das Trennzeichen nicht enthalten. Deshalb macht man da ja auch immer welche drum, falls es doch mal vorkommt. All diese Gefahren nimmt Dir eine Sprache, die das kann, ab.

Liebe Grüße

Erik
Member: Friemler
Friemler Sep 07, 2018 updated at 12:42:33 (UTC)
Goto Top
Hallo @erikro,

ich habe das jetzt erstmal so gelöst (mit Hinweis auf die Einschränkung), weil es evtl. gar nicht notwendig ist, den Aufwand (in VBScript) zu betreiben, um das ganze allgemein verwendbar und damit sicher zu machen. Denn wenn die CSV-Datei keine Felder mit Semikolons in den Nutzdaten enthält, ist alles paletti, ansonsten arbeite ich eben noch mal nach.

Und zu "Sprache, die CSV beherrscht": An Bordmitteln gibt es da nur PowerShell. Der TO schrieb jedoch, dass seine VBScript-Kenntnisse gleich Null sind und er seine letzte Batchdatei vor mindestens 25 Jahren geschrieben hat. Da ist PowerShell sicherlich nicht die richtige Sprache für ein Script, dass er bei Bedarf selbst erweitern will.

Da der TO den genannten Hinweis gab, verstehe ich auch solche Postings nicht, indem ihm in Worten beschrieben wird, wie er ein Script schreiben muss, das sein Problem löst. Aber schon klar, wer Hilfe will, soll einen Dienstleister dafür bezahlen, gelle? Euch haben sie wohl das Modul mit dem Namen "Solidarität" aus dem Gehirn entfernt und durch eins mit der Aufschrift "Geldgeilheit" ersetzt...

Grüße
Friemler
Member: jens-fi
jens-fi Sep 07, 2018 updated at 12:40:19 (UTC)
Goto Top
@ erikro: Danke für die schnelle Antwort. Leider werden die Daten alle in eine Zeile geworfen, also alle ersten Felder, dann alle zweiten Felder ... alles fein säuberlich mit ; getrennt

@ Friemler: PowerShell ISE spuckt mir reihenweise Fehlermeldungen aus, die ich mir mal nach und nach mithilfe der Hilfedateien rausoperieren werde. Wie gesagt, meine Kenntnisse basieren eher auf "Versuch macht Klug".

Die CSV-Dateien enthalten hauptsächlich Adressdaten, also sind die Semikolons nur Trenner.
Member: Friemler
Friemler Sep 07, 2018 at 12:42:05 (UTC)
Goto Top
Zitat von @jens-fi:

@ Friemler: PowerShell ISE spuckt mir reihenweise Fehlermeldungen aus

Mein Code ist kein PowerShell, sondern VBScript. Der Code muss mit der Dateierweiterung VBS abgespeichert werden.

Grüße
Friemler
Member: jens-fi
jens-fi Sep 07, 2018 updated at 12:53:28 (UTC)
Goto Top
Oh, ja da kann das Programm ja nichts dafür, dass der Anwender (ich) zu blöd ist. ;)

Aber um bei "blöd" zu bleiben: Ausführung per Doppelklick? Oder draufziehen? Weil in beiden Fällen ist das Ergebnis folgendes:

Zeile: 1
Zeichen: 1
Fehler: Ungültiges Zeichen
Code: 800A0408
Quelle: Kompilierungsfehler in VBScript
Member: Friemler
Friemler Sep 07, 2018 updated at 13:01:14 (UTC)
Goto Top
Zitat von @jens-fi:

Aber um bei "blöd" zu bleiben: Ausführung per Doppelklick? Oder draufziehen? Weil in beiden Fällen ist das Ergebnis folgendes:

Zeile: 1
Zeichen: 1
Fehler: Ungültiges Zeichen
Code: 800A0408
Quelle: Kompilierungsfehler in VBScript

Die Box mit meinem Script-Code enthält in der oberen rechten Ecke das Wörtchen "Quelltext". Das ist ein Link, der ein neues Browser-Fenster öffnet, das nur den Quelltext ohne Zeilennummern enthält. In das Fenster klicken, CTRL+A und dann CTRL+C drücken, der Quelltext liegt dann in der Zwischenablage. Zum Fenster des Text-Editors wechseln (dafür bitte NICHT MS Word oder ein anderes Textverarbeitungsprogramm verwenden!! Nimm z.B. Windows Notepad) und CTRL+V drücken, dann abspeichern.

Grüße
Friemler
Member: jens-fi
jens-fi Sep 07, 2018 at 13:03:24 (UTC)
Goto Top
Na so weit hatte ich das dann doch schon verstanden. Es ist der reine Quelltext, gespeichert mit dem Editor.
Script-Datei und Quelldatei liegen im selben Verzeichnis.
Member: Friemler
Friemler Sep 07, 2018 at 13:05:50 (UTC)
Goto Top
Wenn es der reine Quelltext wäre, käme die Fehlermeldung nicht. Hier bei mir tut sie es jedenfalls nicht. Hast Du den Quelltext evtl. als Unicode-Datei abgespeichert?
Member: jens-fi
jens-fi Sep 07, 2018 at 13:10:43 (UTC)
Goto Top
Sowas wird's gewesen sein, hab, die Datei noch mal neu erstellt und es läuft. face-smile

Einen kleinen Wunsch hätte ich noch: wenn ich immer die gleiche Datei öffnen will, dann brauche ich das mit dem Draufziehen ja nicht. Kann ich den Dateinamen dann fest einbauen?
Member: erikro
erikro Sep 07, 2018 at 13:21:50 (UTC)
Goto Top
Moin,

Zitat von @jens-fi:

@ erikro: Danke für die schnelle Antwort. Leider werden die Daten alle in eine Zeile geworfen, also alle ersten Felder, dann alle zweiten Felder ... alles fein säuberlich mit ; getrennt

Wie gesagt, war nicht getestet. ;) So gehts:

$old_data = Import-Csv "export.csv" -delimiter ";" -Encoding utf8 # Die Kodierung evtl. anpassen  
foreach($dataset in $old_data) {

   $row = New-Object PSObject -Property @{
   Field1 = $dataset.field1
   Field2 = $dataset.field2
   fullname = $dataset.vorname + " " + $dataset.nachname  
   }
   $row | Export-Csv "bearbeitet.csv" -Delimiter ";" -Encoding utf8 -Append  

}
Member: erikro
erikro Sep 07, 2018 at 13:25:29 (UTC)
Goto Top
Moin,

Zitat von @Friemler:
Da der TO den genannten Hinweis gab, verstehe ich auch solche Postings nicht, indem ihm in Worten beschrieben wird, wie er ein Script schreiben muss, das sein Problem löst. Aber schon klar, wer Hilfe will, soll einen Dienstleister dafür bezahlen, gelle? Euch haben sie wohl das Modul mit dem Namen "Solidarität" aus dem Gehirn entfernt und durch eins mit der Aufschrift "Geldgeilheit" ersetzt...

Ziemlich unverschämt, was Du jemandem schreibst, der hier schon vielen funktionierende Skripts geliefert und mehr als genug beim Debuggen geholfen hat. Ziemlich unverschämt, wenn man dem TO, der keine Ahnung hat statt 12 Zeilen Skript 64 um die Ohren haut, die noch nicht einmal korrekt funktionieren, weil nicht getestet wird, ob ein Datenfeld unerlaubte Zeichen enthält. Wem haben sie hier wohl welches Modul aus dem Hirn entfernt.

PLOP

Erik
Member: Friemler
Friemler Sep 07, 2018 at 13:31:34 (UTC)
Goto Top
Zitat von @jens-fi:

Einen kleinen Wunsch hätte ich noch: wenn ich immer die gleiche Datei öffnen will, dann brauche ich das mit dem Draufziehen ja nicht. Kann ich den Dateinamen dann fest einbauen?

Ich habe das Script oben angepasst.

Grüße
Friemler
Member: Friemler
Friemler Sep 07, 2018 updated at 13:38:44 (UTC)
Goto Top
@erikro

Ich hätte wohl ausdrücklich schreiben müssen, wen ich mit meiner Aussage meinte - Dich jedenfalls nicht. Hatte vorausgesetzt, dass Du das selbst erkennst.

Und wie Du inzwischen wohl schon festgestellt hast, funktioniert mein Script beim TO und genügt auch seinen Ansprüchen.

12 Zeilen kompakter PowerShell-Code sind übrigens von jemandem, der nicht programmieren kann, nur schwer zu verstehen. Kurz ist nicht gleich klar verständlich.

Friemler
Member: jens-fi
jens-fi Sep 07, 2018 updated at 13:41:22 (UTC)
Goto Top
Jetzt macht mal halblang. Ob nun 12 oder 65 Zeilen, das Ergebnis zählt. Und ein massentaugliches Produkt wollte ich nicht haben. Wenn es meine Adressdateien umwandelt, passt das Ergebnis.

BTW: Bei ericos Script kommt das als Ergebnis in der Zieldatei raus:
#TYPE System.Management.Automation.PSCustomObject
"fullname";"Field1";"Field2"  
" ";;  
Member: jens-fi
jens-fi Sep 07, 2018 at 13:40:29 (UTC)
Goto Top
Vielen Dank für das Script, es läuft einwandfrei.

Ich werde jetzt versuchen, es zu verstehen. ;) Ich habe mich seit den 90ern zum Mausschubser entwickelt, alles was da mal an Wissen war, ist ziemlich weg.


Und auch Danke an alle anderen für ihre Ideen und Lösungsansätze.
Member: erikro
erikro Sep 07, 2018 at 13:49:26 (UTC)
Goto Top
Moin,

heißen Deine Felder denn so? Die Feldnamen musst Du schon anpassen und entsprechend mehr in den Block einfügen, in dem das Objekt erzeugt wird. Wenn Deine Datei z. B. diese Überschriften hat:

Wert1;Zahl1;Wert2;Surname;GivenName

dann muss der Code so angepasst werden:

$row = New-Object PSObject -Property @{
   Wert1 = $dataset.Wert1
   Zahl1 = $dataset.Zahl1
   Wert2 = dataset.Wert2
   fullname = $dataset.GivenName + " " + $dataset.Surname  
   }

Liebe Grüße

Erik
Member: Friemler
Friemler Sep 07, 2018 at 14:06:08 (UTC)
Goto Top
Zitat von @jens-fi:

Ich werde jetzt versuchen, es zu verstehen.

Wenn Du nicht weiterkommst - auf dieser Seite gibt es unter der Überschrift "Microsoft Windows Script-Technologien - Hilfe" die Datei script56.chm zum Download. Das ist die Hilfe-Datei zu VBScript und JScript von Microsoft.

Grüße
Friemler