gizmotronix
Goto Top

VBScript: Einzelne Zeile in einer Datei ersetzen (restlicher Inhalt bleibt unangetastet)

Hallo zusammen,

ich versuche seit 3 Tagen für einen speziellen Anwendungsfall in unserem Unternehmen ein Script zu erstellen. Ich habe mit VBScript selbst keine Praxis, kann aber bestehende Scripte halbwegs verstehen und auch anpassen.

Die Aufgabenstellung ist folgende:
Für eine unserer Druckmaschinen müssen Dateien die Informationen zum Druckauftrag enthalten von Umlauten oder Sonderzeichen befreit werden. Sowohl im Dateinamen als auch in der Datei selbst und zwar genau in Zeile 6. Problem dabei ist nur, die Datei darf sich vom Inhalt und Formatierung selbst nicht verändern sondern es soll nur Zeile 6 bearbeitet werden.

Ich habe ein Script nun soweit erstellt was im Grunde auch das gewünschte Ergebnis bringt allerdings nicht fehlerfrei. Die Ursprungsdatei ist 18.623 KB groß und lt. Notepad++ umfasst diese 55.275 Zeilen. Die nach dem Script gespeicherte Datei ist allerdings 37.294 KB und 58.179 Zeilen groß. Kann zwar von der Maschine eingelesen werden, allerdings kommt nur eine schwarze Fläche raus und kein gewünschtes Druckbild.

So sieht der Inhalt der Datei aus:
screen_filecontent

Und das wäre mein aktuelles Script dafür (selbst zusammengebastelt aus div. Beispielen im Netzface-smile

sOrdner = "C:\Test\"  
'sOrdner = "E:\XShare\GenericPressRoot\M600D\"  

' Funktion zum Ersetzen von Sonderzeichen und Umlaute  
Function normalize_str(strRemove)
    Dim arrWrapper(1)
    Dim arrReplace(18)
    Dim arrReplaceWith(18)
    
    arrWrapper(0) = arrReplace
    arrWrapper(1) = arrReplace
    
    ' Replace  
    arrWrapper(0)(0) = "Ä"  
    arrWrapper(0)(1) = "Ö"  
    arrWrapper(0)(2) = "Ü"  
    arrWrapper(0)(3) = "ß"  
    arrWrapper(0)(4) = "ä"  
    arrWrapper(0)(5) = "ö"  
    arrWrapper(0)(6) = "ü"  
    arrWrapper(0)(7) = "~"  
    arrWrapper(0)(8) = "’"  
    arrWrapper(0)(9) = "'"  
    arrWrapper(0)(10) = "/"   
    arrWrapper(0)(11) = "|"  
    arrWrapper(0)(12) = "&"  
	arrWrapper(0)(13) = "!"  
	arrWrapper(0)(14) = "?"  
	arrWrapper(0)(15) = "§"  
	arrWrapper(0)(16) = "$"  
	arrWrapper(0)(17) = "="  
	arrWrapper(0)(18) = "#"  
     
     ' With  
    arrWrapper(1)(0) = "AE"  
    arrWrapper(1)(1) = "OE"  
    arrWrapper(1)(2) = "UE"  
    arrWrapper(1)(3) = "ss"  
    arrWrapper(1)(4) = "ae"  
    arrWrapper(1)(5) = "oe"  
    arrWrapper(1)(6) = "ue"  
    arrWrapper(1)(7) = "_"  
    arrWrapper(1)(8) = "_"  
    arrWrapper(1)(9) = "_"  
    arrWrapper(1)(10) = "_"   
    arrWrapper(1)(11) = "_"  
    arrWrapper(1)(12) = "_"  
	arrWrapper(1)(13) = "_"  
	arrWrapper(1)(14) = "_"  
	arrWrapper(1)(15) = "_"  
	arrWrapper(1)(16) = "_"  
	arrWrapper(1)(17) = "_"  
	arrWrapper(1)(18) = "_"  
    
    For N = 0 To 18
        ' 1: Start find from 1st character  
        ' -1: Find until string does not End  
        ' 0: binary comparision. Respect uppercase from lowercase.  
        strRemove = Replace(strRemove, arrWrapper(0)(N), arrWrapper(1)(N), 1, -1, 0)
    Next
    
    normalize_str = strRemove
End Function

Const ForReading = 1
Const ForWriting = 2
Const TristateUseDefault = -2
intMaxZeile = 6

Set fso = CreateObject("Scripting.FileSystemObject")  
Set objRegEx = CreateObject("VBScript.RegExp")  
' Wir suchen nach dem Wort  CIP3AdmJobName  
objRegEx.Pattern = "CIP3AdmJobName"  

ProcessFolder fso.GetFolder(sOrdner)

Sub ProcessFolder(ThisFolder)
sPath = ThisFolder.Path
If InStr(sPath, "System Volume Information") = 0 Then  
	For Each File In ThisFolder.Files
		sOld = File.Name
		sNew = normalize_str(sOld)
		' sOld ist der alte originale Dateiname  
		' sNew ist der Dateiname ohne Sonderzeichen oder Umlaute aus der Tabelle oben  
	
		If (sNew <> File.Name) then
		  File.Move (File.ParentFolder & "\" & sNew)  
		  ' wenn sNew unterschiedlich zum alten File.Name ist dann wird die Datei umbenannt  
		end if
		
		Set objFile = fso.OpenTextFile(File.ParentFolder & "\" & sNew, ForReading, False, TriStateUseDefault)  
		' wir oeffnen die oben umbenannte Datei um daraus zu lesen  
		count = 0
		' Treffer standardmaessig auf null  
		Do Until objFile.AtEndOfStream
		   ' lauf die Schleife bis zum Ende des Datei-Stream  
		   If count = 1 Then
			Exit Do
			' wenn die Schleife einen Treffer hat dann stoppt sie - da es sonst bei 60000 Zeilen zu lange dauert  
		   End If
		   strSearchString = Mid(objFile.ReadLine,2)
		   ' wir beschneiden den gefunden String um das erste Zeichen / damit es nicht von der Funktion in ein _ verwandelt wird  
		   Set colMatches = objRegEx.Execute(strSearchString)
		   ' wir ermitteln die Ergebnisse indem wir jede Zeile mit dem Suchmuster abgleichen  
		   If colMatches.Count > 0 Then
		    ' gibt es mehr als null Treffe dann mache  
		    For Each strMatch in colMatches
			' fuer jeden gefundenen Eintrag  
			sOldJob = "/" & strSearchString  
			' speicher den Inhalt der originalen Zeile CIP3AdmJobName in die Variable sOldJob und geben wieder in / an den Anfang  
			sJobNew = normalize_str(strSearchString)
			' schicke das ermittelte Ergebnis durch unseren Konverter um Umlaute und Sonderzeichen umzuwandeln  
			sJobNew = "/" & sJobNew  
			' wir speichern den umgewandelten Wert in eine Variable sJobNew und geben wieder ein / an den Anfang  
			Wscript.Echo sJobNew
			count = count + 1
			' Zaehler wird hochgesetzt bei jedem Treffer (sollte nur einen geben)  
		  Next
		 End If
		Loop
		objFile.Close
		
		WScript.Echo sOldJob
		
		intZeile = 1
		Set objFile = fso.OpenTextFile(File.ParentFolder & "\" & sNew, ForReading, False, TriStateUseDefault)  
		Set objDateiSchreiben = fso.CreateTextFile(File.ParentFolder & "\_N_" & sNew, True, True)  
		
		Do Until objFile.AtEndOfStream 'So lange lesen bis zum Schluss  
        strZeile = objFile.ReadLine
        
        If intZeile <= intMaxZeile And InStr(strZeile, sOldJob) Then 'Falls das Wort suchwort in den erst intMaxZeilen Zeilen vorkommt, dann ersetze diese Zeile  
                objDateiSchreiben.WriteLine sJobNew
        Else 'sonst Schreibe einfach die Zeile  
                objDateiSchreiben.WriteLine strZeile
        End If
        
        intZeile = intZeile + 1
		Loop

		objFile.Close
		objDateiSchreiben.Close

	Next
End If
End Sub

Hat hier jemand Tipps und Ideen wie man das Script adaptieren kann oder viell. eine komplett andere Idee wie man dies bewerkstelligen kann ?

Das VBS kann ich dem "Workflow" der diese Datei erzeugt am Ende anhängen damit dies dann auch automatisiert abläuft - daher VBS. Also der Workflow erzeugt die Datei dann muss ich sie mit dem Script überarbeiten und danach wird sie an die Druckmaschine gesendet.

Danke !

lG
Roland

Content-ID: 516601

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

Ausgedruckt am: 24.11.2024 um 01:11 Uhr

emeriks
emeriks 18.11.2019 um 13:05:23 Uhr
Goto Top
Hi,
wenn ich das richtig sehe, dann ist das keine reine Text-Datei, sondern enthält auch Binär-Code. Also darfst Du diese auch nur binär bearbeiten. Also nicht Zeichen ersetzen, sondern Bytes.

Bsp. wie man mit Binärdateien arbeitet: https://www.motobit.com/tips/detpg_read-write-binary-files/

Byte für Byte einlesen und in eine neue Datei schreiben. Dabei ggf. betreffede Bytes ersetzen.

E.
Fennek11
Fennek11 18.11.2019 aktualisiert um 13:41:29 Uhr
Goto Top
In VBA gibt es OPEN file FOR BINARY as #1 um Binar-Dateien zu öffnen. Aber VBA ist recht alt und die Unterstützung von utf-8 ist schlecht. Ist es möglich eine Datei hochzuladen? (http://www.office-loesung.de/p/viewforum.php?f=166). Mit VBS habe ich keine Erfahrung, aber meistens kann VBA in VBS umgeschrieben werden. Käme auch Powershell in betracht?

Noch eine kulturelle Frage: Wäre ein 5-Zeiler akzeptabel oder müssen es unbedingt 50 Zeilen sein?
GizmotroniX
GizmotroniX 18.11.2019 um 14:39:07 Uhr
Goto Top
Hallo Fennek11,

klar, hier ist eine Datei:
https://www.dropbox.com/s/bnee1tyl6q74k5p/PB999994%20Kaufhaeus%20Tueroel ...

5-Zeiler oder 50 Zeilen ist egal, Hauptsache es tut was es soll.
Ich denke halt VBS ist am Besten weil das Script auf einem Server ausgeführt wird und es bei einem anderen Workflow bereits ein solche Konstellation gibt - also wo ein VBS am Ende aufgerufen wird. Somit wärs einheitlich und besser nachvollziehbar in späterer Folge.
GizmotroniX
GizmotroniX 18.11.2019 um 14:41:06 Uhr
Goto Top
Hallo emeriks,

Danke mal für die Info. Puh, da muss ich mich jetzt wieder einlesen wie ich das in das bestehende Script reinnehmen kann ohne wieder von null zu beginnen.

Klar, klingt logisch dass es für Binäre Dateien andere Aufrufe gibt - ich denke auch dass das Problem ist weil er dann beim zeilenweisen Lesen halt auch nicht weiß wo ist die Zeile aus.... und dann erzeugt er mehr Zeilen als eigentlich da sind.
Fennek11
Fennek11 18.11.2019 um 15:18:55 Uhr
Goto Top
sorry, ich lade keine Dateien aus der drop-box.

Hier ein Ansatz mit Powershell:

$fin = 'C:\Users\xxx\Desktop\test.txt'  
$fout = 'C:\Users\xxx\Desktop\test1.txt'  

$Tx = get-content $fin

$DD = New-Object system.collections.hashtable
$DD.add('ä', 'ae')  
$DD.add('ö', 'oe')  
$DD.add('ü', 'ue')  
$DD.add('ß', 'ss')  
$DD.add('Ä', 'Ae')  
$DD.add('Ö', 'Oe')  
$DD.add('Ü', 'Ue')  

foreach ($k in $DD.Keys) {
    $Tx = $tx.replace($k, $DD[$k])}
Set-Content $fout -Value $Tx
emeriks
emeriks 18.11.2019 aktualisiert um 15:31:18 Uhr
Goto Top
Zitat von @Fennek11:
Bis Du sicher, dass Get-Content so einfach mit Binär-Daten klar kommt? Ich denke, da fehlt zum Einen "-Encoding Byte" und zum Anderen dürfte das bei größeren Dateien recht langsam sein. Da wäre es besser, direkt über .NET zu gehen.
Fennek11
Fennek11 18.11.2019 um 16:12:22 Uhr
Goto Top
mangels Datei hatte ich es nur mit UTF8-Text geprüft. Nach dem Bild am Anfang zu urteilen ist die Datei nicht so groß, zehntel Sekunden spielen eh keine Rolle.
Fennek11
Fennek11 18.11.2019 aktualisiert um 22:50:44 Uhr
Goto Top
Einen Code "blind" zu schreiben ist immer ein Risiko:

$fin = 'C:\Users\xxxx\Desktop\test.txt' # <<<< anpassen >>>>  
$fout = 'C:\Users\xxxx\Desktop\test1.txt'        # <<<< anpassen >>>>  
$TT = 100 # Anzahl der Zeichen in ersten 10 Zeilen

$Ta = get-content $fin -Raw # <<<<<<<<<<<<<< Raw auch binary >>>>>>>>
$Tx = $Ta.Substring(0, $TT)

$DD = New-Object system.collections.hashtable
$DD.add('ä', 'ae')  
$DD.add('ö', 'oe')  
$DD.add('ü', 'ue')  
$DD.add('ß', 'ss')  
$DD.add('Ä', 'Ae')  
$DD.add('Ö', 'Oe')  
$DD.add('Ü', 'Ue')  

foreach ($k in $DD.Keys) {$Tx = $Tx.replace($k, $DD[$k])}

$Tx = $Tx -replace "['~´\/|&!\?§$=#]", '_'   

Write-Host "--------------------- `n "  
$Tx 
$Tx = $Tx + $Ta.Substring($TT+1)
Set-Content $fout -Value $Tx
GizmotroniX
GizmotroniX 19.11.2019 um 09:10:27 Uhr
Goto Top
Hallo Fennek11,

Danke mal für die Powershell Variante.
Die erstellte Datei "test1.ppf" sieht zumindest von Dateigröße und Zeilenumfang ident aus mit den Originaldatei "test.ppf". Allerdings klappt die Umwandlung der Umlaute nicht und das "/" am Zeilenanfang oder das "?" in Zeile 1 soll nicht ersetzt werden.

screen

Wenn das mal klappt dann fehlt noch die Umbenennung des Dateinamen selbst (das Script soll alle Dateien des angegeben Ordner verarbeiten) und am Ende soll die Datei unter gleichem Namen gespeichert werden (also test.ppf wird am Ende nach dem Replace wieder zu test.ppf).

Danke !

lG Roland
Fennek11
Fennek11 19.11.2019 um 09:26:56 Uhr
Goto Top
ohne das selbst an Daten, die dem Original nahe kommen, zu testen, kann es nicht werden. Noch einmal, warum lädst Du nicht die ersten 100 Zeilen einer echte Datei an dem angegebenen link hoch?
GizmotroniX
GizmotroniX 19.11.2019 um 09:36:30 Uhr
Goto Top
Zitat von @Fennek11:

warum lädst Du nicht die ersten 100 Zeilen einer echte Datei an dem angegebenen link hoch?

ich hab nicht durchschaut wo ich das hochladen kann ? Ich komme auf die Forenübersicht von office-loesungen.de - dort gibts zwar einen Sticky Thread mit "Dateien hochladen" wo beschrieben ist wie man zu Beiträgen im Forum Dateien hochladen kann aber dazu muss man angemeldet sein.

Soll ich daraus schließen dass ich mich im anderen Forum registrieren, einen Beitrag erstellen und die Datei dort anhängen soll worauf ich dann von hier aus wieder verlinke ? Das ist etwas übertrieben und geht mit Sicherheit auch auf anderem Weg einfacher ...
Fennek11
Fennek11 19.11.2019 um 10:13:04 Uhr
Goto Top
ja, abgesehen davon, dass ich dropbox prinzipiell ablehne, hätte ich mich dort auch registieren müssen.

In dem genannten Forum kann man auch ohne Anmeldung posten, (bitte in code-tags, also [code] xxx [/code]) vielleicht geht das auch mit binär Daten. Probiere es aus.
GizmotroniX
GizmotroniX 19.11.2019 um 10:28:31 Uhr
Goto Top
http://www.office-loesung.de/p/viewtopic.php?f=166&t=823131

Ich habs versucht, soweit ich es aber mit der Original Datei vergleiche wird es in den Code Tags schon anders dargestellt. Ich denke also eine Übermittlung der kompletten Originaldatei macht mehr Sinn. Auf welchem Weg auch immer ... gibts was anderes außer Dropbox und das andere Forum ?
141965
141965 19.11.2019 aktualisiert um 11:47:37 Uhr
Goto Top
Get-ChildItem 'E:\GizmoTronix' -Filter *.ppf -File | %{  
    [regex]::Replace((Get-Content $_.FullName -Raw),'(?im)(?<=/CIP3AdmJobName\s*\()([^\)]+)(?=.*)',{  
        param($m)
        return [regex]::Replace($m.Value,'(?i)^com[1-9]|^lpt[1-9]|^con|^nul|^prn|[\\/:?<>|"*äöüß]',{param($m2) switch -CaseSensitive ($m2){'ä'{'ae'};'ü'{'ue'};'ö'{'oe'};'ß'{'ss'};'Ä'{'Ae'};'Ü'{'Ue'};'Ö'{'Oe'};default{'_'}}})  
    }) | Set-Content $_.FullName -Force
}
Gruß v.
GizmotroniX
GizmotroniX 19.11.2019 um 11:55:55 Uhr
Goto Top
Hallo voucher,

ich habs grad getestet, den Umlaut lässt er stehen, das / bei 3/2019 hat er auf _ ersetzt.

/CIP3AdmJobName (PB999994 Kaufhaus Türol 3/2019 TEST-8) def

lG
Roland
141965
141965 19.11.2019 aktualisiert um 12:03:05 Uhr
Goto Top
Habe es hier mit deiner Original-Datei aus der Dropbox getestet, funktioniert einwandfrei!

screenshot

Ich tippe auf veraltete PS.
GizmotroniX
GizmotroniX 19.11.2019 um 12:05:09 Uhr
Goto Top
OK dann fällt wohl Powershell generell raus weil ich hab hier ein Windows 10 1809 und wenn das "veraltet" ist dann ist das auf dem Server 2012 wo es tatsächlich laufen soll wohl noch problematischer.
141965
141965 19.11.2019 aktualisiert um 12:08:33 Uhr
Goto Top
Zitat von @GizmotroniX:

OK dann fällt wohl Powershell generell raus weil ich hab hier ein Windows 10 1809 und wenn das "veraltet" ist dann ist das auf dem Server 2012 wo es tatsächlich laufen soll wohl noch problematischer.
Nö wende es richtig dann klappt das auch face-smile. Läuft hier auch auf einem 2012R2 ohne Probleme. Ich habe ja deine Originaldatei verwendet, also läuft bei deiner Anwendung was falsch ...

Wieso ihr das nicht im Quellprozess gleich ausmerzt versteht wohl nur ihr.
141965
141965 19.11.2019 aktualisiert um 12:12:22 Uhr
Goto Top
Setz mal das Encoding bei Get-Content passend dann sollte es auch bei dir laufen...
Get-ChildItem 'E:\GizmoTronix' -Filter *.ppf -File | %{  
    [regex]::Replace((Get-Content $_.FullName -Raw -Encoding Default),'(?im)(?<=/CIP3AdmJobName\s*\()([^\)]+)(?=.*)',{  
        param($m)
        return [regex]::Replace($m.Value,'(?i)^com[1-9]|^lpt[1-9]|^con|^nul|^prn|[\\/:?<>|"*äöüß]',{param($m2) switch -CaseSensitive ($m2){'ä'{'ae'};'ü'{'ue'};'ö'{'oe'};'ß'{'ss'};'Ä'{'Ae'};'Ü'{'Ue'};'Ö'{'Oe'};default{'_'}}})  
    }) | Set-Content $_.FullName -Force
}
Alternativ kann man es nat. auch direkt auf Bitebene modifizieren (aufwendiger).
GizmotroniX
GizmotroniX 19.11.2019 um 13:15:45 Uhr
Goto Top
Geht auch nicht wenn ich das Encoding ändere - bei mir bleiben die Umlaute immer erhalten.
Ich habe PSVersion 5.1.17763.771
141965
141965 19.11.2019 aktualisiert um 14:05:59 Uhr
Goto Top
Dann pass das Encoding mal an (UTF8, Unicode usw.), geht hier wie gesagt einwandfrei auf allen Kisten, ansonsten hast du uns nicht das von dir verwendete File zur Verfügung gestellt. Wenn du darin natürlich schon vorher rumpfuschst und erneut anspeicherst führt das ganze hier zu nichts.

Ich bin raus, läuft.
Case solved.
emeriks
emeriks 19.11.2019 um 14:21:45 Uhr
Goto Top
Zitat von @141965:
Case solved.
Was soll der Käse?
GizmotroniX
GizmotroniX 19.11.2019 um 14:39:11 Uhr
Goto Top
Zitat von @141965:

Wenn du darin natürlich schon vorher rumpfuschst und erneut anspeicherst führt das ganze hier zu nichts.


Ach ist das so ? Da weißt du aber mehr als ich ...
Also das ist 1:1 zu gleiche Datei die ich verwende zum Testen welche auch in der Dropbox liegt.

Encoding habe ich schon alles durchprobiert was es an Möglichkeiten gibt - die Datei ist ANSI, also wirds auch nicht hilfreich sein dass in UTF8 oder ASCII oder ähnlichem zu encoden wo ich ohnehin schon Probleme habe das es am Ende verarbeitet werden kann. Aber wie gesagt egal was ich dort angebe es klappt mit den Umlauten nicht. Auch nicht in Powershell 6.x dass ich zwischenzeitlich versucht habe.
141965
141965 19.11.2019 aktualisiert um 17:07:56 Uhr
Goto Top
Damit du siehst das ich hier keine Märchen erzähle, Videobeweis mit Originaldatei (SHA1 Hash: 935b2ba0c9e09ee0e7a98cb5087be826bc3f8e8f):
https://we.tl/t-M7H9oxafOg

Datei hat ein völlig normales Encoding für den Umlaut (ü = 0xFC) auch im Hexeditor geprüft

screenshot

File Compare nach Skriptdurchlauf, links Original, rechts nach Skriptanwendung.

screenshot
rubberman
Lösung rubberman 19.11.2019 aktualisiert um 22:36:13 Uhr
Goto Top
Oh, good old VBScript.
Problem ist, dass alles was irgendwie als Zeilenumbruch verstanden wird, für ReadLine als Abbruchkriterium herangezogen wird. WriteLine macht dann daraus einen Windows Zeilenumbruch bestehend aus den 2 Zeichen Carriage Return und Line Feed. Aber selbst die Plaintextzeilen am Anfang sind nur durch ein einfaches Line Feed Zeichen abgeschlossen.

Ich hab mal deine normalize_str Funktion übernommen, wobei man die auch etwas vereinfachen könnte. Ist aber egal für die 2 Strings die du drüber jagst. Rest ist mehr oder weniger neu. ADO Streams sind hier der Schlüssel, um Binärdaten in einem VBScript zu verarbeiten.

Steffen

Option Explicit

Const sFolder = "C:\Test\"  
Const sFileExt = "ppf"  

Function normalize_str(strRemove)
    Dim arrWrapper(2)
    Dim arrReplace(19)
    Dim arrReplaceWith(19)
    Dim N

    arrWrapper(0) = arrReplace
    arrWrapper(1) = arrReplaceWith

    ' Replace  
    arrWrapper(0)(0) = "Ä"  
    arrWrapper(0)(1) = "Ö"  
    arrWrapper(0)(2) = "Ü"  
    arrWrapper(0)(3) = "ß"  
    arrWrapper(0)(4) = "ä"  
    arrWrapper(0)(5) = "ö"  
    arrWrapper(0)(6) = "ü"  
    arrWrapper(0)(7) = "~"  
    arrWrapper(0)(8) = "’"  
    arrWrapper(0)(9) = "'"  
    arrWrapper(0)(10) = "/"  
    arrWrapper(0)(11) = "|"  
    arrWrapper(0)(12) = "&"  
    arrWrapper(0)(13) = "!"  
    arrWrapper(0)(14) = "?"  
    arrWrapper(0)(15) = "§"  
    arrWrapper(0)(16) = "$"  
    arrWrapper(0)(17) = "="  
    arrWrapper(0)(18) = "#"  

     ' With  
    arrWrapper(1)(0) = "AE"  
    arrWrapper(1)(1) = "OE"  
    arrWrapper(1)(2) = "UE"  
    arrWrapper(1)(3) = "ss"  
    arrWrapper(1)(4) = "ae"  
    arrWrapper(1)(5) = "oe"  
    arrWrapper(1)(6) = "ue"  
    arrWrapper(1)(7) = "_"  
    arrWrapper(1)(8) = "_"  
    arrWrapper(1)(9) = "_"  
    arrWrapper(1)(10) = "_"  
    arrWrapper(1)(11) = "_"  
    arrWrapper(1)(12) = "_"  
    arrWrapper(1)(13) = "_"  
    arrWrapper(1)(14) = "_"  
    arrWrapper(1)(15) = "_"  
    arrWrapper(1)(16) = "_"  
    arrWrapper(1)(17) = "_"  
    arrWrapper(1)(18) = "_"  

    For N = 0 To 18
        ' 1: Start find from 1st character  
        ' -1: Find until string does not End  
        ' 0: binary comparision. Respect uppercase from lowercase.  
        strRemove = Replace(strRemove, arrWrapper(0)(N), arrWrapper(1)(N), 1, -1, 0)
    Next

    normalize_str = strRemove
End Function

Dim objFSO, objFolder, objFile, sFile, sLine
Dim objADOStreamIn1, objADOStreamIn2, objADOStreamOut, objFileStream
Dim newLine, byteCount, lineCount
Const adTypeText = 2
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Const ForReading = 1
Const ForWriting = 2
Const TristateUseDefault = -2
Const sObj = "/CIP3AdmJobName"  
Const iMaxLines = 6
newLine = vbLf

Set objFSO = CreateObject("Scripting.FileSystemObject")  
Set objFolder = objFSO.GetFolder(sFolder)

For Each objFile In objFolder.Files
  sFile = objFile.Name
  ' Wenn Dateiendung passt  
  If StrComp(objFSO.GetExtensionName(sFile), sFileExt, vbTextCompare) = 0 Then
    ' Sonderzeichen ersetzen und umbenennen  
    sFile = normalize_str(sFile)
    objFile.Move(objFile.ParentFolder & "\" & sFile)  

    Set objADOStreamIn1 = CreateObject("ADODB.Stream") ' original Dateiinhalt  
    objADOStreamIn1.Type = adTypeBinary
    objADOStreamIn1.Open

    Set objADOStreamIn2 = CreateObject("ADODB.Stream") ' geänderter Text  
    objADOStreamIn2.Type = adTypeText
    objADOStreamIn2.Charset = "us-ascii"  
    objADOStreamIn2.Open

    Set objADOStreamOut = CreateObject("ADODB.Stream") ' Ausgabe  
    objADOStreamOut.Type = adTypeBinary
    objADOStreamOut.Open

    ' Komplette Datei binär einlesen  
    objADOStreamIn1.LoadFromFile objFile.Path

    ' Dateistream öffnen  
    Set objFileStream = objFile.OpenAsTextStream(ForReading, TriStateUseDefault)
    byteCount = 0
    lineCount = 0
    Do Until objFileStream.AtEndOfStream
      ' raus wenn mehr als 6 Zeilen gelesen wurden aber die Objektkennung nicht gefunden wurde  
      If lineCount > iMaxLines Then Exit Do
      sLine = objFileStream.ReadLine
      ' gelesene Bytes  
      byteCount = byteCount + Len(sLine) + Len(newLine)
      ' gelesene Zeilen  
      lineCount = lineCount + 1
      ' wenn Objektkennung gefunden wurde  
      If InStr(1, sLine, sObj, vbBinaryCompare) = 1 Then
        ' Sonderzeichen entfernen und in den Stream schreiben  
        sLine = normalize_str(sLine)
        objADOStreamIn2.WriteText "/" & Mid(sLine, 2)  
        objADOStreamIn2.WriteText newLine
        ' Raus hier  
        Exit Do
      End If
      ' sonst Zeile in den Stream schreiben  
      objADOStreamIn2.WriteText sLine
      objADOStreamIn2.WriteText newLine
    Loop

    objFileStream.Close

    ' Position in den Originaldaten ändern (Anzahl zu überspringende Zeichen)  
    objADOStreamIn1.Position = byteCount

    ' Textstream zu Binärstream ändern  
    objADOStreamIn2.Position = 0
    objADOStreamIn2.Type = adTypeBinary

    ' Ausgabestream aus geändertem Text und restlichen Binärdaten aufbauen  
    objADOStreamOut.Write objADOStreamIn2.Read
    objADOStreamOut.Write objADOStreamIn1.Read

    ' Datei überschreiben  
    objADOStreamOut.SaveToFile objFile.Path, adSaveCreateOverWrite
    objADOStreamOut.Close
    objADOStreamIn2.Close
    objADOStreamIn1.Close
  End If
Next
GizmotroniX
GizmotroniX 20.11.2019 um 07:56:15 Uhr
Goto Top
Hallo Steffen,

Danke für deine Mühe. Also das Ersetzen klappt soweit - er ersetzt zwar nur Ä durch A oder ö durch o und nicht wie in der Funktion definiert durch oe oder Ae. Ich vermute weil es auf Byte Basis erfolgt ?

Kann man das noch anpassen dass er beim Abspeichern den Dateinamen selbst auch durch die normalize_str Funktion jagt damit auch im Dateinamen die Umlaute und Sonderzeichen umgewandelt werden ?

Danke !
rubberman
rubberman 20.11.2019 aktualisiert um 08:40:12 Uhr
Goto Top
Kann ich nicht nachvollziehen, genauso wenig wie @141965 in seiner PS Lösung. Sollte deine Testdatei nicht dem entsprechen was du in die Dropbox geladen hast, werde ich nicht helfen können. Ich habe mir die Detailfragen, wie Zeichencodierung und verwendeter Zeilenumbruch, mit dem HEX Editor aus dieser Datei selbst beantwortet. Sollte die Realität anders aussehen, geht's in die Hose. Lade dir doch die Datei mal selbst aus der Dropbox und schau dir an ob/wo die Unterschiede liegen. Könnte sein dass dort etwas nicht mehr dem Original entspricht, weil du die Datei nicht in ein ZIP Archiv gepackt hast bevor du sie hochgeladen hast.

Der Effekt den du gerade siehst, hat wahrscheinlich damit zu tun, dass deine Ersetzungsfunktion in deinem Test gar nicht bei Umlauten wirksam wird. Ggf. weil die Zeichencodierung bei dir UTF-8 oder eine völlig andere ist. Dann kommt nur die Charset Eigenschaft des ADO Streams zum tragen, die hier vermutlich aus Umlauten die ASCII Zeichen macht, die denen am nächsten kommen.
Also, nein, ohne reale Datei, die den Fehler reproduzieren kann, ist das nur im Trüben fischen. Keine Ahnung wie ich dir da helfen könnte. Sorry.

Steffen

PS: Ach ja, sollte die Datei OK sein, du aber dein Script nicht ANSI (Windows-1252) codiert haben, sondern ggf. UTF-8, geht es natürlich auch in die Hose.
GizmotroniX
GizmotroniX 20.11.2019 um 09:00:43 Uhr
Goto Top
Ach, Asche auf mein Haupt. Sorry, deine letzte Zeile war die Lösung.
Ich hatte das Thema schon und bin wieder drübergestolpert. Mit ANSI klappts natürlich ohne Probleme mit den Umlauten. Danke noch für den Hinweis.

Somit wäre das Ding mit den Umlauten durch, muss ich nur noch schaffen das die Datei entsprechend ohne Umlaute im Namen gespeichert wird.
emeriks
emeriks 20.11.2019 um 09:15:25 Uhr
Goto Top
Zitat von @GizmotroniX:
Somit wäre das Ding mit den Umlauten durch, muss ich nur noch schaffen das die Datei entsprechend ohne Umlaute im Namen gespeichert wird.
Das wäre dann sicher der komplizierteste Teil ... face-wink
emeriks
emeriks 20.11.2019 aktualisiert um 09:37:28 Uhr
Goto Top
Am Rande:
Dass die neue Datei zwangsläufig größer sein wird, als das Original, ist Dir klar? Nur mal wegen dem Vergleich der Längen und so.
Wenn man ein Zeichen durch zwei ersetzt, dann wird die Datei um min. 1 Byte größer.
rubberman
rubberman 20.11.2019 um 09:29:28 Uhr
Goto Top
Zitat von @GizmotroniX:
muss ich nur noch schaffen das die Datei entsprechend ohne Umlaute im Namen gespeichert wird.
Der Teil mit dem Umbenennen der Datei ist aber nach wie vor im Script und hat bei mir funktioniert.

Steffen
GizmotroniX
GizmotroniX 20.11.2019 um 11:09:53 Uhr
Goto Top
@rubberman
Alles gut, auch der Dateiname wird korrekt umbenannt. Ich werde das Morgen mal in Verbindung mit der Druckmaschine testen und hoffe dass das Thema damit erledigt ist. Vielen Dank nochmal für deine Mühe und Geduld mit den Fragen.

@emeriks
Ich hoffe dass sich diese kleine Änderung in der Größe nicht auswirkt, genau weiß ich es erst nach dem Test an der Maschine wie die Datei eingelesen wird.

@141965
Danke auch Dir nochmal für deinen Einsatz !
rubberman
rubberman 20.11.2019 um 12:02:54 Uhr
Goto Top
Zitat von @GizmotroniX:
Ich hoffe dass sich diese kleine Änderung in der Größe nicht auswirkt

Nach allem was ich gesehen habe, könntest du Glück haben. Anders als bei PDF, sehe ich bei deinem Postscript basierten Format keine Offsets zu den Objekten. Die einzige angegebene Größe ist die des CIP3PreviewImage Objekts (also die der Binärdaten). Dort ändert sich aber nichts.

Steffen
GizmotroniX
GizmotroniX 03.12.2019 um 14:12:25 Uhr
Goto Top
So Leute, ich bin euch noch ne Rückmeldung schuldig. Es hat leider länger gedauert bis wir das Script nun produktiv testen konnten aber die Version von @rubberman funktioniert wie gewünscht. Alle sind happy und ich sage nochmal Danke für die Unterstützung.
rubberman
Lösung rubberman 03.12.2019 um 18:18:49 Uhr
Goto Top
Na super face-smile Wie du gesehen hast, habe ich anhand deiner Datei den Zeilenumbruch als Line Feed Zeichen angenommen und hart im Code stehen. Sollte das bei anderen Dateien mal zu Problemen führen, kannst du ein Stück in die Datei hinein lesen und prüfen was du vorfindest.
Option Explicit

Const sFolder = "C:\Test\"  
Const sFileExt = "ppf"  

Function GetNewLine(ByRef objFile)
  Dim objFileStream, sChar, sCharBefore
  GetNewLine = ""  
  Set objFileStream = objFile.OpenAsTextStream()
  If objFileStream Is Nothing Then Exit Function
  sCharBefore = ""  
  Do While Not objFileStream.AtEndOfStream
    sChar = objFileStream.Read(1)
    If sChar = vbLf Then
      If sCharBefore = vbCr Then GetNewLine = vbCrLf Else GetNewLine = vbLf
      Exit Do
    End If
    sCharBefore = sChar
  Loop
  objFileStream.Close
End Function

Function normalize_str(strRemove)
    Dim arrWrapper(2)
    Dim arrReplace(19)
    Dim arrReplaceWith(19)
    Dim N

    arrWrapper(0) = arrReplace
    arrWrapper(1) = arrReplaceWith

    ' Replace  
    arrWrapper(0)(0) = "Ä"  
    arrWrapper(0)(1) = "Ö"  
    arrWrapper(0)(2) = "Ü"  
    arrWrapper(0)(3) = "ß"  
    arrWrapper(0)(4) = "ä"  
    arrWrapper(0)(5) = "ö"  
    arrWrapper(0)(6) = "ü"  
    arrWrapper(0)(7) = "~"  
    arrWrapper(0)(8) = "’"  
    arrWrapper(0)(9) = "'"  
    arrWrapper(0)(10) = "/"  
    arrWrapper(0)(11) = "|"  
    arrWrapper(0)(12) = "&"  
    arrWrapper(0)(13) = "!"  
    arrWrapper(0)(14) = "?"  
    arrWrapper(0)(15) = "§"  
    arrWrapper(0)(16) = "$"  
    arrWrapper(0)(17) = "="  
    arrWrapper(0)(18) = "#"  

     ' With  
    arrWrapper(1)(0) = "AE"  
    arrWrapper(1)(1) = "OE"  
    arrWrapper(1)(2) = "UE"  
    arrWrapper(1)(3) = "ss"  
    arrWrapper(1)(4) = "ae"  
    arrWrapper(1)(5) = "oe"  
    arrWrapper(1)(6) = "ue"  
    arrWrapper(1)(7) = "_"  
    arrWrapper(1)(8) = "_"  
    arrWrapper(1)(9) = "_"  
    arrWrapper(1)(10) = "_"  
    arrWrapper(1)(11) = "_"  
    arrWrapper(1)(12) = "_"  
    arrWrapper(1)(13) = "_"  
    arrWrapper(1)(14) = "_"  
    arrWrapper(1)(15) = "_"  
    arrWrapper(1)(16) = "_"  
    arrWrapper(1)(17) = "_"  
    arrWrapper(1)(18) = "_"  

    For N = 0 To 18
        ' 1: Start find from 1st character  
        ' -1: Find until string does not End  
        ' 0: binary comparision. Respect uppercase from lowercase.  
        strRemove = Replace(strRemove, arrWrapper(0)(N), arrWrapper(1)(N), 1, -1, 0)
    Next

    normalize_str = strRemove
End Function

Dim objFSO, objFolder, objFile, sFile, sLine
Dim objADOStreamIn1, objADOStreamIn2, objADOStreamOut, objFileStream
Dim newLine, byteCount, lineCount
Const adTypeText = 2
Const adTypeBinary = 1
Const adSaveCreateOverWrite = 2
Const sObj = "/CIP3AdmJobName"  
Const iMaxLines = 6


Set objFSO = CreateObject("Scripting.FileSystemObject")  
Set objFolder = objFSO.GetFolder(sFolder)

For Each objFile In objFolder.Files
  sFile = objFile.Name
  ' Wenn Dateiendung passt  
  If StrComp(objFSO.GetExtensionName(sFile), sFileExt, vbTextCompare) = 0 Then
    ' ermitteln, welcher Zeilenumbruch verwendet wurde  
    newLine = GetNewLine(objFile)
    If newLine <> "" Then  
      ' Sonderzeichen ersetzen und umbenennen  
      sFile = normalize_str(sFile)
      objFile.Move(objFile.ParentFolder & "\" & sFile)  
  
      Set objADOStreamIn1 = CreateObject("ADODB.Stream") ' original Dateiinhalt  
      objADOStreamIn1.Type = adTypeBinary
      objADOStreamIn1.Open
  
      Set objADOStreamIn2 = CreateObject("ADODB.Stream") ' geänderter Text  
      objADOStreamIn2.Type = adTypeText
      objADOStreamIn2.Charset = "us-ascii"  
      objADOStreamIn2.Open
  
      Set objADOStreamOut = CreateObject("ADODB.Stream") ' Ausgabe  
      objADOStreamOut.Type = adTypeBinary
      objADOStreamOut.Open
  
      ' Komplette Datei binär einlesen  
      objADOStreamIn1.LoadFromFile objFile.Path
  
      ' Dateistream öffnen  
      Set objFileStream = objFile.OpenAsTextStream()
      byteCount = 0
      lineCount = 0
      Do Until objFileStream.AtEndOfStream
        ' raus wenn mehr als 6 Zeilen gelesen wurden aber die Objektkennung nicht gefunden wurde  
        If lineCount > iMaxLines Then Exit Do
        sLine = objFileStream.ReadLine
        ' gelesene Bytes  
        byteCount = byteCount + Len(sLine) + Len(newLine)
        ' gelesene Zeilen  
        lineCount = lineCount + 1
        ' wenn Objektkennung gefunden wurde  
        If InStr(1, sLine, sObj, vbBinaryCompare) = 1 Then
          ' Sonderzeichen entfernen und in den Stream schreiben  
          sLine = normalize_str(sLine)
          objADOStreamIn2.WriteText "/" & Mid(sLine, 2)  
          objADOStreamIn2.WriteText newLine
          ' Raus hier  
          Exit Do
        End If
        ' sonst Zeile in den Stream schreiben  
        objADOStreamIn2.WriteText sLine
        objADOStreamIn2.WriteText newLine
      Loop
  
      objFileStream.Close
  
      ' Position in den Originaldaten ändern (Anzahl zu überspringende Zeichen)  
      objADOStreamIn1.Position = byteCount
  
      ' Textstream zu Binärstream ändern  
      objADOStreamIn2.Position = 0
      objADOStreamIn2.Type = adTypeBinary
  
      ' Ausgabestream aus geändertem Text und restlichen Binärdaten aufbauen  
      objADOStreamOut.Write objADOStreamIn2.Read
      objADOStreamOut.Write objADOStreamIn1.Read
  
      ' Datei überschreiben  
      objADOStreamOut.SaveToFile objFile.Path, adSaveCreateOverWrite
      objADOStreamOut.Close
      objADOStreamIn2.Close
      objADOStreamIn1.Close
    End If
  End If
Next
Nur so als Ergänzung. Keine Ahnung ob das jemals der Fall sein könnte.

Steffen
GizmotroniX
GizmotroniX 04.12.2019 um 06:36:05 Uhr
Goto Top
Super, Danke für den Nachtrag im Script. Könnte hilfreich sein wenns mal ein Update gibt wo sich viell. die Umbrüche ändern.