Helmer 1 Geschrieben 16. September Autor Melden Teilen Geschrieben 16. September Danke für Eure Antworten. Es gilt, eine komplette Nachricht, welche einen Suchstring enthält, als Block zu exportieren. Die Struktur ist recht einfach. Eine Nachricht fängt immer mit dem MSH-Segment (am Zeilenanfang) an und endet mit dem nächsten MSH-Segment der nächsten Nachricht, innerhalb einer Archivdatei (es sind einige hundert Nachrichten pro Archivdatei). Das Lösen per Queue oder Array scheint mir Erfolg versprechend zu sein. Bei mir scheitert es an der korrekten Syntax für die Umsetzung (veranschaulicht am Stand in meinem letzten Post). Ich finde auch nicht wirklich viel beim großen „G“, in Verbindung mit Powershell und der Queue. Wie sich ein -split dazu hinreißen lässt, den Datenstrom bei einem gefundenen Suchstring zu unterbrechen und den entsprechenden Datensatz komplett (MSH > MSH) zu exportieren, finde ich spannend, da dieser Ansatz sehr „smart“ ausschaut. Z.B. der Suchstring „7909264350“ wird im PV1-Segment des Beispiels unten (Zitat) gefunden, nun sollte die komplette hervorgehobene Nachricht (von MSH > MSH) exportiert werden. Es ist durchaus möglich, dass der Suchstring mehrfach in der Archivdatei vorhanden ist (alle betreffenden Datensätze/Nachrichten komplett exportieren). Bisher wird dies manuell umgesetzt, Suchstring gefunden, ein paar Zeilen hoch (MSG-Segment vor dem Suchstring), markiert inklusive zur letzten Zeile der Nachricht (Zeile vor dem nächsten MSG-Segment), kopieren und in eine neue Datei einfügen. Zitat Archivdateibeispiel (sehr stark gekürzt): MSH|^~\&|MEL PID|1||7903313686| PV1|1||^^^^^^^^2825||||||||||||||||7909260637| ORC|OK|WKC097U|WKC097U- OBR|1|WKC097U|WKC097U-1 OBX|1|ST|BI-032^Erreg OBR|2|WKC097U|WKC097U OBX|1|ST|BI-685^Staph OBR|3|WKC097U|WKC097U OBX|1|ST|BI-PROT1^Bef NTE|1|L|Kulturelles W MSH|^~\&|ME PID|1||7902183713| PV1|1||^^^^^^^^2938||||||||||||||||7909264350| ORC|OK|WKC058S|WKC OBR|1|WKC058S|WKC0 OBX|1|ST|BI-032^Er OBR|2|WKC058S|WKC0 OBX|1|ST|BI-603^Prot OBR|3|WKC058S|WKC058S OBX|1|ST|BI-PROT1^Bef NTE|1|L|Kulturelles Wach OBR|4|WKC058S|WKC058S-1| OBX|1|ST|BI-PROT2^Befund NTE|1|L|Antibiogramm sie OBR|5|WKC058S|WKC058S-1| OBX|1|ST|BI-ICD109^ICD10 NTE|1|L|A40-A41 Bakterie NTE|2|L|T82.7 Sepsis bei MSH|^~\&|ME PID|1||7903126877| PV1|1||^^^^^^^^2825||||||||||||||||7909265076| ORC|OK|WKC118D|WKC OBR|1|WKC118D|WKC1 OBX|1|ST|BI-032^Er OBR|2|WKC118D|WKC1 OBX|1|ST|BI-673^St OBR|3|WKC118D|WKC1 OBX|1|ST|BI-PROT1^ NTE|1|L|Zusätzlich OBR|4|WKC118D|WKC1 OBX|1|NM|BI-ATB^An OBR|5|WKC118D|WKC1 OBX|1|ST|BI-RES^Me NTE|1|L|Antibiogra NTE|2|L|Wirkstoff NTE|3|L|Penicillin NTE|4|L|Oxacillin NTE|5|L|Ampicillin Zitieren Link zu diesem Kommentar
testperson 1.707 Geschrieben 16. September Melden Teilen Geschrieben 16. September Liest du auch Antworten und versuchst ansatzweise etwas Energie da reinzustecken? $LogFile = "C:\Install\Test\Log.txt" $LogContent = Get-Content -Path $LogFile ` -Raw $Content = $LogContent -split "(?=MSH\|)" | Where-Object { -not [string]::IsNullOrEmpty($_) } $i = 1 $Content -match "\|7902183713\|" | ForEach-Object { Write-Host "Ich bin gefundener Block Nr.: $i`n" $_ $i++ } (Das lässt sich sicherlich noch optimieren, sofern Bedarf besteht und das Auswerten der Logs wirklich zeitkritisch sein sollte.) Zitieren Link zu diesem Kommentar
Dukel 455 Geschrieben 16. September Melden Teilen Geschrieben 16. September $LogFile = "d:\powershell\hl7.log" $SuchString = "MSH" $bloecke = @() $block = "" foreach ($i in Get-Content -Path $LogFile){ if($i -like "$SuchString*"){ # Neuer Block $bloecke += $block $block = "" }else{ $block += $i } } $bloecke[0] # Z.b. der erste Block $bloecke[3] # Z.b. der vierte Block $bloecke[-1] # Z.b. der letzte Block Zitieren Link zu diesem Kommentar
Beste Lösung daabm 1.366 Geschrieben 16. September Beste Lösung Melden Teilen Geschrieben 16. September (bearbeitet) Dein Fehler war nur das fehlende Verständnis für "Contains". Das gilt nur für Arrays, und der Vergleichswert muss einem _kompletten_ Element des Arrays entsprechen. $SampleData = "$env:TEMP\SampleData.txt" $Reader = [IO.StreamReader]::new( $SampleData ) $Results = [Collections.Arraylist]::new() $Queue = [Collections.Queue]::new() $BlockMarker = 'MSH' $MatchString = "PID" $MatchFound = $false While ( $SampleLine = $Reader.ReadLine() ) { $Queue.Enqueue( $SampleLine ) If ( $SampleLine -match $MatchString ) { $MatchFound = $true } If ( $SampleLine -match $BlockMarker ) { If ( $MatchFound ) { [void] $Results.Add(( $Queue.ToArray() )) } $Queue.Clear() $MatchFound = $false $Queue.Enqueue( $SampleLine ) } } $Reader.Dispose() Das steckt solange Zeilen in die Queue, bis ein "MSH" gefunden wird. Wenn unterwegs ein "PID" vorbeikam, wird die Queue in $Result gespeichert. Dann zurück auf Los Das meinte ich mit meinem vorigen Post Du mußt eine Logik finden und korrekt implementieren, die die Aufgabe auch löst. Edit: Nachträglich von Get-Content auf StreamReader geändert, ist einfach Lichtjahre schneller... Nachtrag: Natürlich geht das auch mit Regex Multiline. Aber da sind wir wieder bei der Wartbarkeit, Regex hat da seine eigenen Tücken. Hab irgendwo mal ein Regex aufgeschnappt, das ich nicht mehr finde - das konnte alle Arten von Kommentaren aus C++-Sourcecode entfernen. War aber komplett unverständlich... bearbeitet 16. September von daabm Zitieren Link zu diesem Kommentar
NorbertFe 2.061 Geschrieben 16. September Melden Teilen Geschrieben 16. September vor 1 Stunde schrieb daabm: War aber komplett unverständlich... logisch, wenns regex ist. ;) Zitieren Link zu diesem Kommentar
daabm 1.366 Geschrieben 16. September Melden Teilen Geschrieben 16. September vor 11 Minuten schrieb NorbertFe: logisch, wenns regex ist. ;) "NorbertFe" -match "^N[o].+e" Regex hat viele "Geschmäcker". Die einfachen sind echt "handy", weil Regex halt für Stringmassage gemacht ist. Aber wenn man dann Lazy/Greedy und vielleicht noch Backward nutzt, nested und named Matches verwendet, wird's schnell unübersichtlich. Zitieren Link zu diesem Kommentar
Helmer 1 Geschrieben 17. September Autor Melden Teilen Geschrieben 17. September vor 8 Stunden schrieb daabm: Dein Fehler war nur das fehlende Verständnis für "Contains". Das gilt nur für Arrays, und der Vergleichswert muss einem _kompletten_ Element des Arrays entsprechen. $SampleData = "$env:TEMP\SampleData.txt" $Reader = [IO.StreamReader]::new( $SampleData ) $Results = [Collections.Arraylist]::new() $Queue = [Collections.Queue]::new() $BlockMarker = 'MSH' $MatchString = "PID" $MatchFound = $false While ( $SampleLine = $Reader.ReadLine() ) { $Queue.Enqueue( $SampleLine ) If ( $SampleLine -match $MatchString ) { $MatchFound = $true } If ( $SampleLine -match $BlockMarker ) { If ( $MatchFound ) { [void] $Results.Add(( $Queue.ToArray() )) } $Queue.Clear() $MatchFound = $false $Queue.Enqueue( $SampleLine ) } } $Reader.Dispose() Das steckt solange Zeilen in die Queue, bis ein "MSH" gefunden wird. Wenn unterwegs ein "PID" vorbeikam, wird die Queue in $Result gespeichert. Dann zurück auf Los Das meinte ich mit meinem vorigen Post Du mußt eine Logik finden und korrekt implementieren, die die Aufgabe auch löst. Edit: Nachträglich von Get-Content auf StreamReader geändert, ist einfach Lichtjahre schneller... Nachtrag: Natürlich geht das auch mit Regex Multiline. Aber da sind wir wieder bei der Wartbarkeit, Regex hat da seine eigenen Tücken. Hab irgendwo mal ein Regex aufgeschnappt, das ich nicht mehr finde - das konnte alle Arten von Kommentaren aus C++-Sourcecode entfernen. War aber komplett unverständlich... Danke dir / euch, ich würde mir das Ganze einmal durch die Hirnwindungen jagen und versuchen zu finalisieren. Danke für den Tipp mit dem "Contains" .... hat mich doch recht lange beschäftigt... Nur gut, dass auch andere sich mit / bei den Regex nicht zu Hause fühlen. vor 7 Stunden schrieb NorbertFe: logisch, wenns regex ist. ;) .... ich schaue mal, wie weit ich komme. Zitieren Link zu diesem Kommentar
Helmer 1 Geschrieben 17. September Autor Melden Teilen Geschrieben 17. September (bearbeitet) Durch die massive Unterstützung von euch, schaut nun eine Lösung so aus: $SampleData = "c:\temp\Schnittstelle\oru.log" $Reader = [IO.StreamReader]::new( $SampleData ) $Results = [Collections.Arraylist]::new() $Queue = [Collections.Queue]::new() $BlockMarker = 'MSH' $MatchString = "7909265176" $MatchFound = $false While ( $SampleLine = $Reader.ReadLine() ) { $Queue.Enqueue( $SampleLine ) If ( $SampleLine -match $MatchString ) { $MatchFound = $true } If ( $SampleLine -match $BlockMarker ) { If ( $MatchFound ) { [void] $Results.Add(( $Queue.ToArray() )) $Zeilen = $Queue.Count for($i= 0; $i -lt $Zeilen -1 ; $i++) { $Queue.Dequeue() >> c:\temp\Schnittstelle\ORU_$(Get-Date -Format yyyy-MM-dd.hh.mm.ss).log } } $Queue.Clear() $MatchFound = $false $Queue.Enqueue( $SampleLine ) } } $Reader.Dispose() Es waren nur noch kleine Anpassungen zu dem fast fertigen Script von Martin nötig. In der Ausgabe ist immer die erste Zeile (MSH-Segment) der nächsten Nachricht mit ausgegeben worden. Ein Löschen des letzten Eintrags der $Queue ist mir nicht möglich gewesen, weshalb ich eine Schleife eingebaut habe, die die Queue (Einträge / Zeilen -1) ausgibt. Meinen herzlichen Dank an euch - Habt Ihr eine virtuelle Kaffeedose mit Schlitz für eine Spende? Helmer bearbeitet 17. September von Helmer 1 Zitieren Link zu diesem Kommentar
Empfohlene Beiträge
Schreibe einen Kommentar
Du kannst jetzt antworten und Dich später registrieren. Falls Du bereits ein Mitglied bist, logge Dich jetzt ein.