none
Anonymisierungsskript sehr langsam RRS feed

  • Frage

  • Hallo,

    ich habe das Problem das mein geschriebenes Anonymisierungsskript sehr langsam läuft. Ich habe hier Text-Dateien die bis zu 500mb groß sein können und wenn ich bei 5mb schon mehr als 2 Stunden brauche ist das halt nicht wirklich praktikabel.

    Erstmal zu den Daten, hier eine kleines Beispiel zum Aufbau (immer nach 2048 Zeichen kommt ein Zeilenumbruch):

    Segment1.0'Segment2.0'Segment3.0'Segment4.0'Segment5.0'Segment6.0'Segment7.0'Segment1.1'Segment2.1'Segment3.1'Segment4.1'Segment5.1'Segment1.2'Segment2.2'Segment3.2'Segment4.2'Segment5.2'

    Ich habe mir gedacht ich mache erstmal für jedes Segment eine Zeile und gehe dann einfach jede Zeile durch und frage ab ob am Anfang dieser Zeile NAD+* oder VIN+* steht, wenn ja wird NAD+* durch "NAD+XXXXXXXX:YYYYYYYY'" und VIN+* durch "VIN+Z$VINCOUNTER'" ersetzt.

    Nur dieses Foreach Schleife braucht so lange, kann ich das irgendwie eleganter lösen?

    $INDATA = "D:\EINGABE.TXT"
    $OUTDATA = "D:\TEST.TXT"
    Remove-Item -Path "D:\TEST.TXT"
    $TEMPDATA = "D:\TMP.TXT"
    Remove-Item -Path "D:\TMP.TXT"
    $SOURCEFILE = $null
    $ANONYMDATA = $null
    [int]$VINCOUNTER = 100000000
    $AUF = Get-Content -Path "$INDATA" | Select-Object -Index 0
    $SOURCEFILE = [System.IO.File]::ReadallLines($INDATA) | Select-Object -Skip 1
    $SOURCEFILE = $SOURCEFILE -replace "`r`n", $null
    $SOURCEFILE = $SOURCEFILE -replace "'", "'`r`n"  
    [System.IO.File]::WriteAllText($TEMPDATA, $SOURCEFILE,[System.Text.Encoding]::Default)
    $SOURCEFILE = $null
    $SOURCEFILE = [System.IO.File]::ReadallLines($TEMPDATA)
    foreach($line in $SOURCEFILE){
        if($line -like 'NAD+*')
            {
             $ANONYMDATA = $ANONYMDATA + "NAD+XXXXXXXX:YYYYYYYY'"
            }
        else
            {    
             if($line -like 'VIN+*')
                {
                 $ANONYMDATA = $ANONYMDATA + "VIN+Z$VIN'"
                 $VIN = Get-Random -Minimum 100000000 -Maximum 999999999
                }
             else
                {
                 $ANONYMDATA = $ANONYMDATA + $line
                }
            }
    }
    [System.IO.File]::WriteAllText($OUTDATA, $ANONYMDATA,[System.Text.Encoding]::Default)


    Ich hoffe mir kann hier geholfen werden.

    Grüße hRoICE


    • Bearbeitet hRoICE Freitag, 26. Januar 2018 11:46 Skript änderung
    Freitag, 26. Januar 2018 09:54

Antworten

  • Ok, dann versuche doch folgendes:

    'NAD\+[^']*'
    'VIN\+[^']*'

    ".*" steht leider für beliebige Zeichen, also auch Hochkommata.
    "[^']*" steht für beliebige Zeichen außer Hochkomma, so dass davor aufgehört wird.

    Mittwoch, 31. Januar 2018 13:36
  • Moin,

    so, ich habe die Ergebnisse der Diskussion mal einem Leistungstest unterzogen. Das Ergebnis ist ganz interessant, ich werde es die Tage mal aufbereiten und bloggen. Aber das Fazit ist wie folgt:

    Wenn (unter der generellen Annahme, dass die zu anonymisierenden Daten selbst keine Apostrophen enthalten)

    1. die relevanten Felder nirgends durch einen Zeilenumbruch unterbrochen werden (sprich: alles von VIN+ bzw. NAD+ bis inkl. des darauffolgenden Apostrophs befindet sich stets auf einer Zeile), und

    2. die Zeilen werden durch das Ersetzen weder verlängert noch verkürzt

    dann solltest Du die Variante

    Get-Content -Path "C:\TEMP\EINGABE.TXT" -ReadCount 500 | foreach { ($_ -Replace "'NAD\+.*'"  , "'NAD+XXXXXXXX:YYYYYYYY'") -Replace "'VIN\+.*'" , ("'VIN+Z" + (Get-Random -Minimum 100000000 -Maximum 999999999) + "'")} | set-content "C:\TEMP\AUSGABE.txt"

    nehmen. Die Zahl hinter -ReadCount ist dabei relativ egal und beeinflusst weder die Laufzeit noch den RAM-Verbrauch des Ganzen, solange sie mindestens dreistellig ist. Ich konnte aber keinen Unterschied zwischen 100 und 1000 feststellen.

    Wenn aber eine der beiden obigen Annahmen nicht zutreffen, kannst Du entweder mein Skript unten so wie es ist nehmen oder versuchen, die beiden Ansätze zu verheiraten. Aber viel wird es nicht mehr bringen.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 20:02
  • So jetzt aber, richtig klasse. Brauche jetzt für 100mb nur noch 22 Sekunden.

    Get-Date -Format HH:mm:ss
    $inputfile = "D:\INDATA.TXT"
    $tempfile = "D:\ANONYMTEMP.TXT"
    Remove-Item -Path "$tempfile"
    $outputfile = "D:\OUTDATA.TXT"
    Remove-Item -Path "$outputfile"
    $DATAOUT = $null
    $DATA = $null
    $writer = New-Object System.IO.StreamWriter($OutputFile, $false,([System.Text.Encoding]::Default))
    
    $DATA = [System.IO.File]::ReadallText($inputfile)
    $DATA = $DATA -replace "\r\n", $null
    $DATA = $DATA -replace "NAD\+[^']*"  , "NAD+XXXXXXXX:YYYYYYYY"
    $DATA = $DATA -replace "VIN\+[^']*" , "VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)"
    [System.IO.File]::WriteAllText($tempfile, $DATA,[System.Text.Encoding]::Default)
    $DATA = [System.IO.File]::ReadallLines($tempfile)
    [INT]$COUNTER = ($DATA | Measure-Object -char).Characters[0]
    for([INT]$COUNTER2 = 0;$COUNTER2 -lt $COUNTER;$COUNTER2 = $COUNTER2 + $RECORDSIZE)
             {
              IF($COUNTER2+$RECORDSIZE -ge $COUNTER)
                {
                 $RECORDSIZE = $COUNTER - $COUNTER2
                 $writer.WriteLine($DATA.Substring($COUNTER2,$RECORDSIZE))          
                }
              ELSE
                {
                 $writer.WriteLine($DATA.Substring($COUNTER2,$RECORDSIZE))
                }
             }
    $Writer.Close()
    Get-Date -Format HH:mm:ss

    Danke ;)


    • Bearbeitet hRoICE Freitag, 2. Februar 2018 09:03 "'", "'`r`n" entfernt + -replace "\r\n", $null
    • Als Antwort markiert hRoICE Freitag, 16. März 2018 12:19
    Dienstag, 30. Januar 2018 16:17

Alle Antworten

  • Moin,

    Du wirst auf jeden Fall schneller ans Ziel, wenn Du die Dateien nicht ganz einliest und ganz rausschreibst, sondern eben genau den Bereich, den Du bearbeitest. Dafür eignen sich die Klassen "StreamReader" und "StreamWriter" sehr gut.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 10:06
  • Moin,

    wie genau funktioniert dieser StreamReader? Ich habe dazu keine wirklich gut Beschreibung gefunden.

    Grüße hRoICE

    Freitag, 26. Januar 2018 12:00
  • Moin,

    alles im MSDN beschrieben: https://msdn.microsoft.com/de-de/library/system.io.streamwriter(v=vs.110).aspx und https://msdn.microsoft.com/de-de/library/system.io.streamreader(v=vs.110).aspx

    Hier mal ein Snippet, der eine große Datei (es ging um eine ca. 450 GB große Textdatei) in kleinere Stücke aufteilt:

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$false)][ValidateScript({Test-Path $_ -PathType Leaf})][string]$InputFile,
        [Parameter(Mandatory=$false)][ValidateScript({Test-Path $_ -PathType Container})][string]$OutputPath,
        [Parameter(Mandatory=$false)][int]$LinesPerFile = 10000
    )
    $name = (Get-Item $InputFile).BaseName
    $extension = (Get-Item $InputFile).Extension
    $reader = New-Object System.IO.StreamReader($InputFile)
    $filecount = 1
    $newfile = $true
    while(($line = $reader.ReadLine()) -ne $null) {
        if ($newfile) {
            $outfile = "$OutputPath\$($name)_$($filecount.ToString().PadLeft(8,'0'))$extension"
            $writer = New-Object System.IO.StreamWriter($outfile,$false,([System.Text.Encoding]::UTF8))
            "Creating file $outfile"
            $linecount = 0
            $newfile = $false
            $filecount++
        }
        $linecount++
        $writer.WriteLine($line)
        if ($linecount -eq $LinesPerFile) { 
            $newfile = $true 
            $writer.Close()
        }
    }
    $writer.Close()
    $reader.Close()


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 12:55
  • Die Frage ist, ob die Begriffe NAD+ und VIN+ in jeder einzelne Zeile immer paarweise vorkommen.
    Dann kannst du die Bearbeitung bereits innerhalb der ReadLine-Schleife durchführen und sparst dir das ganze Replace, denn die Hochkommatas sind ja nicht relavant sondern nur die beiden Vorkommen.

    Wenn die Reihenfolge von NAD+ und VIN+ immer dieselbe ist, kann man das auch in einem Like zusammenfassen:

    like "NAD+*VIN+"

    und schreibst direkt dein Anonymergebnis.

    Freitag, 26. Januar 2018 13:59
  • Dadurch das ich hinter jedem ' ein Zeilenumbruch setzte, habe ich jedes Segmentteil in einer Zeile.

    So sieht das dann aus:

    SEG1.1+'
    SEG1.2+'
    SEG1.3+'
    SEG1.4+'
    VIN+'
    NAD+'
    SEG1.7+'
    SEG1.8+'
    .
    .
    .
    SEG1.24+'
    SEG2.1+'
    SEG2.2+'
    SEG2.3+'
    SEG2.4+'
    SEG2.5+'
    VIN+'
    NAD+'
    SEG2.8+'
    SEG2.9+'
    .
    .
    .
    SEG2.84+'

    Wenn ich das mit dem StreamReader richtig verstehe, lese ich da doch nur nur bestimmt Daten ein und schreibe Sie wieder raus. Das hilft mir doch nicht oder? Ich will ja das meine Datei gleich bleibt und ich will nur bestimmt Segmente verändern. Ich habe jetzt noch was dazu gebaut, das am ende die Daten nicht in einer Zeile sind, sondern nach 2048 Zeichen ein Zeilenumbruch eingebaut wird. Damit ist die Datei dann vom Aufbau wie vorher nur das jetzt alle NAD und VIN Felder mit Anonymendaten gefüllt sind.

    Leider braucht mein Skript 30 min für nur 5mb und das ist nicht wirklich zielführend.

    Grüße hRoICE


    • Bearbeitet hRoICE Freitag, 26. Januar 2018 14:23 was vergessen!
    Freitag, 26. Januar 2018 14:21
  • Dann gehts noch einfacher;-).

    https://stackoverflow.com/questions/16250258/replace-the-content-of-a-textfile-with-a-regex-in-powershell

    Wobei du das Replace nach der Pipe wiederholen kannst.
    Jetzt musst du nur noch überlegen, wie genau die Ausdrücke des NAD+ und VIN+ zu definieren sind.

    Wenn du dazu ein paar Bespiele bereitstellst fällt uns bestimmt was ein.

    Freitag, 26. Januar 2018 14:35
  • Wenn ich das mit dem StreamReader richtig verstehe, lese ich da doch nur nur bestimmt Daten ein und schreibe Sie wieder raus. Das hilft mir doch nicht oder?

    Doch, das macht Deinen Shit schneller, und das ist es doch, was Du wolltest. Verändern musst Du die Daten natürlich zwischendurch. Mein Beispiel tut es nicht, weil es nicht die Aufgabe war...

    Kannst Du vielleicht mal ein wirkliches Beispiel Deiner Rohdaten posten, vielleicht mit etwas veränderten personenbezogenen Inhalten? Das würde das Verständnis Deines Problems erleichtern, glaube ich.

    Das Handling der Tatsache, dass die "Textdatei-Zeilen" (2048-Zeichen-Blöcke) nicht an den Grenzen der Segmente enden, hat Dich dazu veranlasst, zuerst alles zusammen zu schieben, dann durchzugehen und dann alles wieder aufzuteilen. Das ist nicht optimal und fällt Dir gerade  performance-mäßig auf die Füße.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 14:55
  • Moin,

    probier mal diesen und schau, wie das tut. Vor allem, ob sich die Durchlaufzeit (wird in jedem Loop ausgegeben) zum Ende hin verlängert:

    $timer = [System.Diagnostics.Stopwatch]::StartNew()
    $inputfile = "C:\TEMP\ndvin.txt"
    $outputfile = "C:\TEMP\ndvin2.txt"
    $i = 0
    $bufferlen = 2048
    $buffer = ""
    $pre = ""
    $reader = New-Object System.IO.StreamReader($InputFile)
    $writer = New-Object System.IO.StreamWriter($OutputFile, $false,([System.Text.Encoding]::UTF8))
    $timer = [System.Diagnostics.Stopwatch]::StartNew()
    while(($line = $reader.ReadLine()) -ne $null) {
        $t = $timer.Elapsed.TotalMilliseconds
        $zline = ""
        if ($pre) {
            $break = $line.IndexOf("'")
            if ($break -ge 0) {
                $zline = $pre + $line.Substring(0,$break + 1)
                $pre = $line.Substring($break + 1)
            } else {
                $pre += $line
            }
        } else {
            if ($line.EndsWith("'")){
                $zline = $line
            } else {
                $pre = $line
            }
        }
        $zline = ($zline -replace  "NAD\+.*'","NAD+XXXXXXXX:YYYYYYYY'") -replace  "VIN\+.*'","VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'"
        $buffer += $zline
        while ($buffer.Length -ge $bufferlen) {
            $writer.WriteLine($buffer.Substring(0, ($bufferlen - 1)))
            $buffer = $buffer.Substring($bufferlen)
        } $i++ "$i : $($timer.Elapsed.TotalMilliseconds - $t)" } if ($pre) { $buffer += ($pre -replace "NAD\+.*'","NAD+XXXXXXXX:YYYYYYYY'") -replace "VIN\+.*'","VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'" } if ($buffer.Length -gt 0) { do { if ($buffer.Length -ge $bufferlen) { $writer.WriteLine($buffer.Substring(0, ($bufferlen - 1))) $buffer = $buffer.Substring($bufferlen) } else { $writer.WriteLine($buffer) $buffer = "" } } until ($buffer.Length -eq 0) } $reader.Close() $writer.Close() "Elapsed: $($timer.Elapsed.TotalMilliseconds)"


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.




    Freitag, 26. Januar 2018 16:35
  • Warum so kompliziert, er will doch nur 2 Zeichenketten in der Datei ersetzen, eine di mit NAD+ anfängt, eine die mit VIN+ anfängt.

    Dazu muss man nun wissen, wie der generelle Aufbau denn aussieht. Man könnte aber auch davon ausgehen, dass diese Begriffe immer in Hochkomma eingeschlossen sind, also:

    'NAD+XXXXXX:YYYYYYY' = "'NAD\+.*'"
    'VIN+xxxxx' = "'VIN\+.*'"

    Also

    $content = Get-Content -path "MyFile.CSV" $content -Replace "'NAD\+.*'" , "'NAD+XXXXXXXX:YYYYYYYY'"
    | -Replace "'VIN\+.*'" , "'VIN+Z" + Get-Random -Minimum 100000000 -Maximum 999999999 + "'"
    | Out-File "MyNewFile.CSV"

    Freitag, 26. Januar 2018 17:04
  • Warum so kompliziert, 

    ...weil

    1. es darum geht, das für eine große Datei zu machen. Sowohl Get-Content als auch Out-File werden hier performance-mäßig scheitern. Und auch die Verarbeitung von 300.000 Zeilen im RAM.

    2. Get-Content einen Array of Strings produziert, und es ist nicht so, dass ein Feld immer komplett in einer Zeile enthalten ist

    3. das Ersetzte nicht zwangsläufig die gleiche Länge hat wie der ersetzende Text, somit die Zeilenlänge in der Ausgabe "verzogen" wären


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 17:14
  • Zu 2) und 3) dürft das ziemlich egal sein, da dies auch in obigem Code egal ist.

    Und zu 1)

    Get-Content -path "MyFile.CSV"
    |
    -Replace
    "'NAD\+.*'" , "'NAD+XXXXXXXX:YYYYYYYY'"
    | -Replace "'VIN\+.*'" , "'VIN+Z" + Get-Random -Minimum 100000000 -Maximum 999999999 + "'"
    | set-content "MyNewFile.CSV"

    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content?view=powershell-5.1

    Mittels der Option "-ReadCount" könnte man ggf. noch bzgl. der Perofmance experimentieren.
    Mit "-ReadCount 500" werden erst 500 Zeilen gelesen und direkt an die Pipe geleitet.
    Klar sollte ich get-content dann nicht erst in eine Variable packen.

    Freitag, 26. Januar 2018 17:32
  • Zu 2) und 3) dürft das ziemlich egal sein, da dies auch in obigem Code egal ist.

    Falsch. In meinem Code werden beide korrekt behandelt.

    Im Code des TO wird 2) korrekt, aber performance-technisch sehr inoptimal, behandelt, indem jedes Feld in eine einzelne Zeile kommt und vorher der Array of Strings in einen einzigen String zusammengefasst wird.

    3) mag egal sein, sofern die Ausgangsdaten fixe Länge haben und man diese Länge in den anonymisierten Daten auch beibehält.

    Dein Beispiel mit den Pipes ist übrigens syntaktisch nicht ganz richtig, denn -replace ist ein Operator und kann nicht gleich in der Pipe stehen. Richtig wäre

    ((Get-Content -path "MyFile.CSV") -Replace "'NAD\+.*'"  , "'NAD+XXXXXXXX:YYYYYYYY'") -Replace "'VIN\+.*'" , ("'VIN+Z" + (Get-Random -Minimum 100000000 -Maximum 999999999) + "'") | set-content "MyNewFile.CSV"


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.


    • Bearbeitet Evgenij Smirnov Freitag, 26. Januar 2018 18:03 noch eine Klammer vergessen ;-)
    Freitag, 26. Januar 2018 17:52
  • Sogar noch übersichtlicher. Und wenn get-content (wie beschrieben) direkt Zeile für Zeile an set-content weitergibt ist das doch eigentlich ok und müsste auch performant sein.

    Und nach dieser Aussage:

    "Ich habe mir gedacht ich mache erstmal für jedes Segment eine Zeile und gehe dann einfach jede Zeile durch und frage ab ob am Anfang dieser Zeile NAD+* oder VIN+* steht, wenn ja wird NAD+* durch "NAD+XXXXXXXX:YYYYYYYY'" und VIN+* durch "VIN+Z$VINCOUNTER'" ersetzt."

    wird ein "Segment" nicht durch NewLine unterbrochen und enthält einen der gesuchten Werte.

    Der Inhalt ist ein EDI-Format dass ich in einer anderen Sprache auch schon mal importieren musste.

    Freitag, 26. Januar 2018 18:33
  • Sogar noch übersichtlicher. Und wenn get-content (wie beschrieben) direkt Zeile für Zeile an set-content weitergibt ist das doch eigentlich ok und müsste auch performant sein.

    Ist es aber leider nicht, jedenfalls (noch) nicht in der Fassung. Dadurch, dass es keine Pipe ist, kann man -ReadCount nicht direkt verwenden, höchstens mit foreach:

    Get-Content -path "C:\TEMP\ndvin.txt" -ReadCount 500 | foreach { ($_ -Replace "'NAD\+.*'"  , "'NAD+XXXXXXXX:YYYYYYYY'") -Replace "'VIN\+.*'" , ("'VIN+Z" + (Get-Random -Minimum 100000000 -Maximum 999999999) + "'")} | set-content "C:\TEMP\ndvin4_500.txt"

    Und da ist es mit ReadCount tatsächlich performant genug.

    Und nach dieser Aussage:

    "Ich habe mir gedacht ich mache erstmal für jedes Segment eine Zeile und gehe dann einfach jede Zeile durch und frage ab ob am Anfang dieser Zeile NAD+* oder VIN+* steht, wenn ja wird NAD+* durch "NAD+XXXXXXXX:YYYYYYYY'" und VIN+* durch "VIN+Z$VINCOUNTER'" ersetzt."

    wird ein "Segment" nicht durch NewLine unterbrochen und enthält einen der gesuchten Werte.

    Genau. Ich MACHE ERSTMAL eine Zeile. Ich meine, die Zeilenlänge von 2048 ist doch zufällig und hat mit den Daten nichts zu tun. Somit kann jedes Segment beliebig durch Newline unterbrochen sein.

    Aber da möge sich der TO mal äußern, ob das passiert oder nicht. Denn davon wird abhängen, ob man das inhaltlich so machen kann oder nicht.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 18:58
  • Moin,

    so, ich habe die Ergebnisse der Diskussion mal einem Leistungstest unterzogen. Das Ergebnis ist ganz interessant, ich werde es die Tage mal aufbereiten und bloggen. Aber das Fazit ist wie folgt:

    Wenn (unter der generellen Annahme, dass die zu anonymisierenden Daten selbst keine Apostrophen enthalten)

    1. die relevanten Felder nirgends durch einen Zeilenumbruch unterbrochen werden (sprich: alles von VIN+ bzw. NAD+ bis inkl. des darauffolgenden Apostrophs befindet sich stets auf einer Zeile), und

    2. die Zeilen werden durch das Ersetzen weder verlängert noch verkürzt

    dann solltest Du die Variante

    Get-Content -Path "C:\TEMP\EINGABE.TXT" -ReadCount 500 | foreach { ($_ -Replace "'NAD\+.*'"  , "'NAD+XXXXXXXX:YYYYYYYY'") -Replace "'VIN\+.*'" , ("'VIN+Z" + (Get-Random -Minimum 100000000 -Maximum 999999999) + "'")} | set-content "C:\TEMP\AUSGABE.txt"

    nehmen. Die Zahl hinter -ReadCount ist dabei relativ egal und beeinflusst weder die Laufzeit noch den RAM-Verbrauch des Ganzen, solange sie mindestens dreistellig ist. Ich konnte aber keinen Unterschied zwischen 100 und 1000 feststellen.

    Wenn aber eine der beiden obigen Annahmen nicht zutreffen, kannst Du entweder mein Skript unten so wie es ist nehmen oder versuchen, die beiden Ansätze zu verheiraten. Aber viel wird es nicht mehr bringen.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Freitag, 26. Januar 2018 20:02
  • Moin,

    frisch aus dem Wochenende zurück und wieder auf der Arbeit. Finde es erstmal sehr cool diesen Austausch hier zu lesen und vielen danke für die Hilfe. Ich hoffe ich kann alle Fragen beantworten und habe auch paar Fehler in meinem Code gefunden.

    Erstmal zum Aufbau der Daten. Richtig ist das jede Zeile 2048 Zeichen lang ist und das Segment natürlich durch das in 2048 Zeichen pressen durch eine Zeilenumbruch unterbrochen werden kann, das passiert natürlich auch sehr oft. Deswegen hatte ich mir überlegt das es am besten ist diese Zeilenumbrüche zu entfernen.

    $SOURCEFILE = $SOURCEFILE -replace "`r`n", $null

    Beispiel vor Replace:

    SEG1.1+'SEG1.2+'SEG1.3+'SEG1.4+'VIN+'NAD+'...SEG1.34+HAL(Zeilenumbruch)
    LO'SEG1.35+'

    und nach Replace:

    SEG1.1+'
    SEG1.2+'
    SEG1.3+'
    SEG1.4+'
    VIN+'
    NAD+'
    .
    .
    .
    SEG1.34+HAL LO'
    SEG1.35+'

    Richtig wäre Ohne Leerzeichen zwischen HALLO (SEG1.34+HALLO')

    $SOURCEFILE = [System.IO.File]::ReadallLines($INDATA)
    
    foreach($line in $SOURCEFILE){
    $DATAWITHOUTRETURN = $DATAWITHOUTRETURN + $line
    }
    $DATAWITHRETURN = $DATAWITHOUTRETURN -replace "'", "'`r`n"
    
    [System.IO.File]::WriteAllText($TEMPDATA, $DATAWITHRETURN,[System.Text.Encoding]::Default)

    Deswegen hatte ich mir jetzt gedacht das mir dann eine Foreach schleifen hilft. Ist natürlich bei eine 5mb Datei super und funktioniert auch. Aber bei einer 100mb Datei dann wieder nicht.

    Das Skript von Evgenij Smirnov habe ich auch mal getestet, die Datei die Dabei raus kommt sieht sehr gut aus. Aber ich gebe eine Datei mit 49812 Zeilen mit einer länge von 2048 Zeichen rein (99,721 mb) und raus kommt nur eine Datei mit 3585 Zeilen mit einer länge von 2048 Zeichen (7,172 mb). Aber schnell ist es für die 49812 Zeilen braucht Powershell nur knapp eine Minute.

    Da scheint etwas nicht zu stimmen, ich kann leider nur nicht feststellen was falsch ist, weil meine Kenntnisse noch nicht so groß sind.

    Ich hoffe ich habe nichts vergessen zu beantworten.

    Montag, 29. Januar 2018 12:40
  • Dann würde ich das doch etwas anders machen (insbesonders das verketten der Zeilen dauert ewig):

    [System.IO.File]::ReadallText($INDATA)
    | $_ replace "\r\n", ""
    -Replace "'NAD\+.*'"  , "'NAD+XXXXXXXX:YYYYYYYY'")
    -Replace "'VIN\+.*'" , ("'VIN+Z" + (Get-Random -Minimum 100000000 -Maximum 999999999) + "'")
    | for ($i = 0; $i -lt $_.Length; $i+= 2048; { $_.Substring( $i, 2048) }
    | set-content $OUTDATA

    Man benötigt zwar viel Hauptspeicher (in der Größe der Datei * 3) aber das Problem sind halt die NewLines im Text irgendwo.

    ReadallText => lädt den gesamten Text incl. der NewLines komplett in den Speicher in einer Variablen.
    Anschließend wird der Inhalt 3 * kopiert und dabei ersetzt.
    In der Schleife zerlegst du das dann wieder in Blöcke a 2K, die set-content wieder mit newline ausgibt.

    100MB in den Speicher zuladen und durchzuscannen sollte jetzt nicht das Problem sein.

    Syntaxfehller nicht ausgeschlossen;-).


    Montag, 29. Januar 2018 13:47
  • Ich habe mal noch etwas gebaut und sehe jetzt ist nur noch das nach 2048 Zeichen ein Zeilenumbruch machen,das was das Skript langsam macht.

    Get-Date -Format HH:mm:ss
    $inputfile = "D:\BLA.TXT"
    $outputfile = "D:\BLUB.TXT"
    $DATAOUT = $null
    
    $DATA = [System.IO.File]::ReadallText($inputfile)
    $DATA = $DATA -replace "\r\n", $null
    $DATA = $DATA -replace "'", "'`r`n"
    $DATA = $DATA -replace "NAD\+.*'"  , "NAD+XXXXXXXX:YYYYYYYY'"
    $DATA = $DATA -replace "VIN\+.*'" , "VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'"
    $DATA = $DATA -replace "\r\n", ""
    [System.IO.File]::WriteAllText($outputfile, $DATA,[System.Text.Encoding]::Default)
    $DATA = [System.IO.File]::ReadallLines($outputfile)
    
    [INT]$COUNTER = ($DATA | Measure-Object -char).Characters[0]
    for([INT]$COUNTER2 = 0;$COUNTER2 -lt $COUNTER;$COUNTER2 = $COUNTER2 + 2048)
             {
              [INT]$ROWLENGTH = 2048
              IF($COUNTER2+$ROWLENGTH -ge $COUNTER)
                {
                 $ROWLENGTH = $COUNTER - $COUNTER2
                 $DATAOUT = $DATAOUT + $DATA.Substring($COUNTER2,$ROWLENGTH)            
                }
              ELSE
                {
                 $DATAOUT = $DATAOUT + $DATA.Substring($COUNTER2,$ROWLENGTH) + [System.Environment]::NewLine
                }
             }
    [System.IO.File]::WriteAllText($outputfile, $DATAOUT,[System.Text.Encoding]::Default)
    Get-Date -Format HH:mm:ss

    Also 5mb gehen in nicht mal 20 sek durch aber 100mb laufen jetzt schon 15 min. Das natürlich nicht cool.

    Montag, 29. Januar 2018 15:35
  • Das Ersetzen der Hochkommata mit "\r\n" kannst du dir ja sparen.
    Ebenso das wiedereinführen der "\r\n".
    In den Ursprungsreplace beginnt der Begriff jeweils mit Hochkomma und endet auch mit diesem (es sei denn, diese sind so nicht in der Quelle).
    Und können daher problemlos ersetzt werden.

    Also:
    1. Einlesen und \r\n entfernen
    2. Replace NAD+ und VIN+
    3. Ausgeben in 2K-Blöcken mit \r\n (automatisch durch WriteLine)

    Wenn die NAD+ und VIN+ nicht mit Hochkomma enden, so muss der Suchbegriff genuso als Muster definiert werden, wie die Begriffe aussehen (Länge und Typ der Zeichen).
    Dazu wäre ein paar Beispiele hilfreich.

    Montag, 29. Januar 2018 20:17

  • 3. Ausgeben in 2K-Blöcken mit \r\n (automatisch durch WriteLine)


    Moin,

    Punkt 3 ist das einzige was ich nicht verstehe, ich habe mal eine bissel mit WriteLine experimentiert. Aber ich habe keine Parameter gefunden um Ihm zu sagen das er das in 2048 Zeichenblöcke ausgeben soll.

    [System.IO.File]::WriteAllLines($outputfile, $DATAOUT,[System.Text.Encoding]::Default)

    Dienstag, 30. Januar 2018 08:54
  • So sollte es gehen;-).
    for ($i = 0; $i -lt $DATAOUT.Length; $i+= 2048; 
    { [System.IO.File]::WriteLine($DATAOUT.Substring( $i, 2048) ,[System.Text.Encoding]::Default) }

    Dienstag, 30. Januar 2018 09:15
  • So sollte es gehen;-).
    for ($i = 0; $i -lt $DATAOUT.Length; $i+= 2048; 
    { [System.IO.File]::WriteLine($DATAOUT.Substring( $i, 2048) ,[System.Text.Encoding]::Default) }

    Problem daran ist das die Schleife genau wie meine funktioniert. Nur das die Sachen gleich in einen Datei geschrieben werden. Aber auch immer wieder überschrieben werden und damit nur die letzte Zeile in der Datei steht. Es gibt zwar AppendAllText macht die Sache jetzt auch nicht schneller. Ich brauche etwas was schnell den langen String teilt und dann in einen Datei schriebt.
    Dienstag, 30. Januar 2018 10:26
  • Moin,

    probier mal diesen und schau, wie das tut. Vor allem, ob sich die Durchlaufzeit (wird in jedem Loop ausgegeben) zum Ende hin verlängert:

    $timer = [System.Diagnostics.Stopwatch]::StartNew()
    $inputfile = "C:\TEMP\ndvin.txt"
    $outputfile = "C:\TEMP\ndvin2.txt"
    $i = 0
    $bufferlen = 2048
    $buffer = ""
    $pre = ""
    $reader = New-Object System.IO.StreamReader($InputFile)
    $writer = New-Object System.IO.StreamWriter($OutputFile, $false,([System.Text.Encoding]::UTF8))
    $timer = [System.Diagnostics.Stopwatch]::StartNew()
    while(($line = $reader.ReadLine()) -ne $null) {
        $t = $timer.Elapsed.TotalMilliseconds
        $zline = ""
        if ($pre) {
            $break = $line.IndexOf("'")
            if ($break -ge 0) {
                $zline = $pre + $line.Substring(0,$break + 1)
                $pre = $line.Substring($break + 1)
            } else {
                $pre += $line
            }
        } else {
            if ($line.EndsWith("'")){
                $zline = $line
            } else {
                $pre = $line
            }
        }
        $zline = ($zline -replace  "NAD\+.*'","NAD+XXXXXXXX:YYYYYYYY'") -replace  "VIN\+.*'","VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'"
        $buffer += $zline
        while ($buffer.Length -ge $bufferlen) {
            $writer.WriteLine($buffer.Substring(0, ($bufferlen - 1)))
            $buffer = $buffer.Substring($bufferlen)
        } $i++ "$i : $($timer.Elapsed.TotalMilliseconds - $t)" } if ($pre) { $buffer += ($pre -replace "NAD\+.*'","NAD+XXXXXXXX:YYYYYYYY'") -replace "VIN\+.*'","VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'" } if ($buffer.Length -gt 0) { do { if ($buffer.Length -ge $bufferlen) { $writer.WriteLine($buffer.Substring(0, ($bufferlen - 1))) $buffer = $buffer.Substring($bufferlen) } else { $writer.WriteLine($buffer) $buffer = "" } } until ($buffer.Length -eq 0) } $reader.Close() $writer.Close() "Elapsed: $($timer.Elapsed.TotalMilliseconds)"


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.




    Ich habe mir das Skript nochmal angeguckt und wenn ich eine Datei wo sich jedes Segment in einer Zeile befindet dann funktioniert es auch. Aber leider sehr sehr langsam. Ich brauche für 5mb mit meinem Skript 19 Sekunden und mit deinem Skript dauert es 5 min ich denke mit einer 100 mb Datei ist es dann noch langsamer.

    Schade eigentlich, aber vielleicht kennt ja einer noch was, was man machen könnte.

    Dienstag, 30. Januar 2018 10:30
  • Dann nimm, wie oben vorgeschlagen einen Writer und schreibe mit diesem die 2K-Blöcke in der Schleife.
    Dienstag, 30. Januar 2018 10:50
  • Dann nimm, wie oben vorgeschlagen einen Writer und schreibe mit diesem die 2K-Blöcke in der Schleife.

    Hatte ich doch schon beschrieben, wenn ich das mit deiner Schleife mache wird nur die letzte Zeile in die Datei eingetragen. Weil er beim Writer (also ich denke mal du meinst "[System.IO.File]::WriteAllLines") die Datei immer neu anlegt. Man kann das jetzt mit [System.IO.File]::AppendAllText machen, bringt aber auch nichts ist auch langsamer.

    [INT]$COUNTER = ($DATA | Measure-Object -char).Characters[0]
    for ([int]$i = 0; $i -lt $COUNTER; $i+= 2048)
    {
    $DATAOUT = $DATA.Substring($i,2048) + [System.Environment]::NewLine
    [System.IO.File]::AppendAllText($outputfile,$DATAOUT,[System.Text.Encoding]::Default)
    } 
    Das Problem ist die for-Schleife, die ist einfach zu langsam.

    Dienstag, 30. Januar 2018 11:29
  • So jetzt habe ich es, macht genau das was es soll und es kommt auch wieder eine schöne Datei raus.

    100mb brauchen da nur 4 min, das natürlich klasse.

    Get-Date -Format HH:mm:ss
    $inputfile = "D:\INDATA.TXT"
    $tempfile = "D:\ANONYMTEMP.TXT"
    Remove-Item -Path "$tempfile"
    $outputfile = "D:\BLUB.TXT"
    Remove-Item -Path "$outputfile"
    $DATAOUT = $null
    $DATA = $null
    
    $DATA = [System.IO.File]::ReadallText($inputfile)
    $DATA = $DATA -replace "\r\n", $null
    $DATA = $DATA -replace "'", "'`r`n"
    $DATA = $DATA -replace "NAD\+.*'"  , "NAD+XXXXXXXX:YYYYYYYY'"
    $DATA = $DATA -replace "VIN\+.*'" , "VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'"
    $DATA = $DATA -replace "\r\n", $null
    [System.IO.File]::WriteAllText($tempfile, $DATA,[System.Text.Encoding]::Default)
    $DATA = [System.IO.File]::ReadallLines($tempfile)
    [INT]$COUNTER = ($DATA | Measure-Object -char).Characters[0]
    for([INT]$COUNTER2 = 0;$COUNTER2 -lt $COUNTER;$COUNTER2 = $COUNTER2 + 2048)
             {
              [INT]$ROWLENGTH = 2048
              IF($COUNTER2+$ROWLENGTH -ge $COUNTER)
                {
                 $ROWLENGTH = $COUNTER - $COUNTER2
                 $DATAOUT = $DATA.Substring($COUNTER2,$ROWLENGTH)
                 [System.IO.File]::AppendAllText($outputfile,$DATAOUT,[System.Text.Encoding]::Default)            
                }
              ELSE
                {
                 $DATAOUT = $DATA.Substring($COUNTER2,$ROWLENGTH) + [System.Environment]::NewLine
                 [System.IO.File]::AppendAllText($outputfile,$DATAOUT,[System.Text.Encoding]::Default)
                }
             }
    Get-Date -Format HH:mm:ss

    Danke für eure Hilfe.

    Dienstag, 30. Januar 2018 12:50
  • Moin,

    bei großen Dateien ist in den RAM laden und dann komplett rausschreiben immer ein Fehler. Ich habe mir jetzt den Spaß gemacht und eine 100MB große Datei (50.000 Zeilen) erzeugt. Das obige Skript, etwas abgewandelt (die Ersetzung hat nicht richtig funktioniert, habe es wieder auf Split/Join umgebaut) hat ziemlich genau 2 Minuten gebraucht.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Dienstag, 30. Januar 2018 13:05
  • Willst du nicht oder kannst du nicht;-)?

    Lass einfach ein paar Zeilen weg:

    Get-Date -Format HH:mm:ss $inputfile = "D:\INDATA.TXT" $tempfile = "D:\ANONYMTEMP.TXT" Remove-Item -Path "$tempfile" $outputfile = "D:\BLUB.TXT" Remove-Item -Path "$outputfile" $DATAOUT = $null $DATA = $null $DATA = [System.IO.File]::ReadallText($inputfile) $DATA = $DATA -replace "\r\n", $null $DATA = $DATA -replace "'NAD\+.*'" , "'NAD+XXXXXXXX:YYYYYYYY'" $DATA = $DATA -replace "'VIN\+.*'" , "'VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'"

    $writer = New-Object System.IO.StreamWriter($OutputFile, $false,([System.Text.Encoding]::UTF8))

    for ($i = 0; $i -lt $DATA.Length; $i+= 2048;
    { $writer.WriteLine($DATAOUT.Substring( $i, 2048) }

    $Writer.Close()

    Get-Date -Format HH:mm:ss

    Da du ja schon alles im Speicher hast (ReadAllText), brauchst du keine weitere Zwischendatei.
    Zusätzlich wird AppendAllText immer langsamer, je größer die Datei dann wird, da das Ende immer gesucht werden muss.
    Mit dem Writer bist du immer am Ende der Datei.


    Dienstag, 30. Januar 2018 13:11
  • Moin,

    bei großen Dateien ist in den RAM laden und dann komplett rausschreiben immer ein Fehler. Ich habe mir jetzt den Spaß gemacht und eine 100MB große Datei (50.000 Zeilen) erzeugt. Das obige Skript, etwas abgewandelt (die Ersetzung hat nicht richtig funktioniert, habe es wieder auf Split/Join umgebaut) hat ziemlich genau 2 Minuten gebraucht.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Moin,

    toll kannst du mir das mal zu Verfügung stellen?

    Grüße hRoICE

    Dienstag, 30. Januar 2018 13:23
  • Willst du nicht oder kannst du nicht;-)?

    Lass einfach ein paar Zeilen weg:

    Get-Date -Format HH:mm:ss $inputfile = "D:\INDATA.TXT" $tempfile = "D:\ANONYMTEMP.TXT" Remove-Item -Path "$tempfile" $outputfile = "D:\BLUB.TXT" Remove-Item -Path "$outputfile" $DATAOUT = $null $DATA = $null $DATA = [System.IO.File]::ReadallText($inputfile) $DATA = $DATA -replace "\r\n", $null $DATA = $DATA -replace "'NAD\+.*'" , "'NAD+XXXXXXXX:YYYYYYYY'" $DATA = $DATA -replace "'VIN\+.*'" , "'VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)'"

    $writer = New-Object System.IO.StreamWriter($OutputFile, $false,([System.Text.Encoding]::UTF8))

    for ($i = 0; $i -lt $DATA.Length; $i+= 2048;
    { $writer.WriteLine($DATAOUT.Substring( $i, 2048) }

    $Writer.Close()

    Get-Date -Format HH:mm:ss

    Da du ja schon alles im Speicher hast (ReadAllText), brauchst du keine weitere Zwischendatei.
    Zusätzlich wird AppendAllText immer langsamer, je größer die Datei dann wird, da das Ende immer gesucht werden muss.
    Mit dem Writer bist du immer am Ende der Datei.


    Doch ich will, aber bei meinem Skript versaut er mir dann die Datei. Ich versuche aber auch gerne nochmal deinen weg den du hier beschrieben hast. Vielleicht wird es ja noch schneller. Man kann ja immer was dazu lernen ;) Danke
    • Bearbeitet hRoICE Dienstag, 30. Januar 2018 13:27 fehler
    Dienstag, 30. Januar 2018 13:27
  • So jetzt aber, richtig klasse. Brauche jetzt für 100mb nur noch 22 Sekunden.

    Get-Date -Format HH:mm:ss
    $inputfile = "D:\INDATA.TXT"
    $tempfile = "D:\ANONYMTEMP.TXT"
    Remove-Item -Path "$tempfile"
    $outputfile = "D:\OUTDATA.TXT"
    Remove-Item -Path "$outputfile"
    $DATAOUT = $null
    $DATA = $null
    $writer = New-Object System.IO.StreamWriter($OutputFile, $false,([System.Text.Encoding]::Default))
    
    $DATA = [System.IO.File]::ReadallText($inputfile)
    $DATA = $DATA -replace "\r\n", $null
    $DATA = $DATA -replace "NAD\+[^']*"  , "NAD+XXXXXXXX:YYYYYYYY"
    $DATA = $DATA -replace "VIN\+[^']*" , "VIN+Z$(Get-Random -Minimum 100000000 -Maximum 999999999)"
    [System.IO.File]::WriteAllText($tempfile, $DATA,[System.Text.Encoding]::Default)
    $DATA = [System.IO.File]::ReadallLines($tempfile)
    [INT]$COUNTER = ($DATA | Measure-Object -char).Characters[0]
    for([INT]$COUNTER2 = 0;$COUNTER2 -lt $COUNTER;$COUNTER2 = $COUNTER2 + $RECORDSIZE)
             {
              IF($COUNTER2+$RECORDSIZE -ge $COUNTER)
                {
                 $RECORDSIZE = $COUNTER - $COUNTER2
                 $writer.WriteLine($DATA.Substring($COUNTER2,$RECORDSIZE))          
                }
              ELSE
                {
                 $writer.WriteLine($DATA.Substring($COUNTER2,$RECORDSIZE))
                }
             }
    $Writer.Close()
    Get-Date -Format HH:mm:ss

    Danke ;)


    • Bearbeitet hRoICE Freitag, 2. Februar 2018 09:03 "'", "'`r`n" entfernt + -replace "\r\n", $null
    • Als Antwort markiert hRoICE Freitag, 16. März 2018 12:19
    Dienstag, 30. Januar 2018 16:17
  • Wobei du dir diese beiden doch sparen kannst:

    $DATA = $DATA -replace "'", "'`r`n"
    $DATA = $DATA -replace "\r\n", $null
    

    Die sind für die Konvertierung doch nicht relevant.

    Dienstag, 30. Januar 2018 17:28
  • Wobei du dir diese beiden doch sparen kannst:

    $DATA = $DATA -replace "'", "'`r`n"
    $DATA = $DATA -replace "\r\n", $null
    

    Die sind für die Konvertierung doch nicht relevant.

    Hätte ich auch gedacht. Das Weglassen führt aber dazu, dass das "richtige" Replace nicht wie erwartet funktioniert.

    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Dienstag, 30. Januar 2018 19:05
  • hm, kann ich irgendwie nicht nachvollziehen:

    -replace "'NAD\+.*'" , "'NAD+XXXXXXXX:YYYYYYYY'"

    Beim RegEx wird genau der Begriff gesucht, der mit Hochkomma anfängt und auch aufhört und mit einem neuen Begriff, der von Hochkomma eingeschlossen ist ersetzt.

    Ein Ersetzen von Hochkomma mit "Hochkomma + NewLine" macht da keinen Unterschied außer, dass mit "NAD+" statt "'NAD+" begonnen werden muss, da das Hochkomma ja nun von einem NewLine verfolgt wird.

    Mittwoch, 31. Januar 2018 08:17
  • Moin,

    Ich glaube aber das wenn das alles in einer Zeile steht, wie es ja zu diesem Zeitpunkt ist, replaced er alles ab NAD+* bis zum letzten ' des Strings. Da es sich ja nur um einen String handelt, löscht er dir alles andere weg. Scheinbar ist die Logik von Powershell bei -replace so aufgebaut.

    Wenn aber ein Zeilenumbruch kommt, durchsucht er halt nur diese Zeile und da ist das letzte ' auch das ende vom NAD-Segment und somit funktioniert das -replace wie es soll.

    Anders kann ich es mir nicht wirklich erklären.

    Mittwoch, 31. Januar 2018 11:52
  • Ok, dann versuche doch folgendes:

    'NAD\+[^']*'
    'VIN\+[^']*'

    ".*" steht leider für beliebige Zeichen, also auch Hochkommata.
    "[^']*" steht für beliebige Zeichen außer Hochkomma, so dass davor aufgehört wird.

    Mittwoch, 31. Januar 2018 13:36
  • Moin,

    cool ja das funktioniert, danke für die Info und die Erklärung.

    Grüße hRoICE

    Donnerstag, 1. Februar 2018 11:43
  • Bei der Flut an 1A Hilfe die du hier bekommen hast, wärs jetzt schön wenn du noch die Beiträge die dir geholfen mit "Hilfreich" markierst und die die letztendlich zur Lösung geführt haben, als Antwort.

    Grüße, Denniver.


    Blog: http://bytecookie.wordpress.com

    Kostenloser Powershell Code Manager v5: Link
    (u.a. Codesnippets verwalten + komplexe Scripte graphisch darstellen)

    Hilf mit und markiere hilfreiche Beiträge mit dem "Abstimmen"-Button (links) und Beiträge die eine Frage von dir beantwortet haben, als "Antwort" (unten).
    Warum das Ganze? Hier gibts die Antwort.

    Samstag, 3. Februar 2018 11:44
    Moderator