- Offizieller Beitrag
Hi,
folgende Problemstellung als Bsp.:
Ein Text enthält unbekannt viele Werte eines bestimmten Musters (z.B. ZAHLENWERT-SPACE-EINHEIT_KG) jetzt möchte ich alle diese Kg-Angaben in Gramm umwandeln.
Die Matches per RegExp zu finden ist kein Problem.
Mein Gedanke war nun, kann ich mit StringRegExpReplace während des Parsens den Match manipulieren und Replace mit dem geänderten Wert durchführen? Jein. Ich kann das führ den ersten Match durchführen, muß dann aber wieder den kpl. String weiterparsen, bis alle Vorkommen bearbeitet und ersetzt sind. Und zusätzlich muß ich das Pattern so aufbauen, dass auch immer der kpl. Text in Backreferenzen gecaptured wird damit ich den zu manipulierenden Wert auch abgreifen kann ohne dass der Rest verloren geht. Bei Texten mit einigen 1000 Zeilen ist mir diese Methode deutlich zu aufwändig (Ressourcen-verbratend).
Nächster Gedanke: Per Offset-Parsing die Fundstellen und Matches ermitteln und zwischenspeichern. Mit den Offset-Infos die Teilstrings selektieren, den Match manipulieren und einen neuen Ergebnisstring zusammensetzen. Das funktioniert auch - allerdings bei größeren Dimensionen (Text auf 6500 Zeilen mit 3800 Matches) werden bei mir ca. 30 s benötigt (inkl. Konsolenausgabe).
Vielleicht habt ihr eine Idee, wie man das performanter gestalten kann.
Bei ein paar hundert Zeilen Text ist das kein Problem, somit in der überwiegenden Zahl der Anwendungsfälle ausreichend. Ich muß aber z.B. öfter Maschinen-Logs abgrasen und da wäre es durchaus schick, wenns auch schneller geht.
Hier mal meine Lösung, in dem Bsp-String ersetze ich Zahlenwerte in eckigen Klammern mit dem Wert*1000:
Spoiler anzeigen
$s = "abc[1] gjj66 h [20]j4l7l3 l[3]-g9 j[80lh[444][5]k21k]kq" ; alle Zahlen in eckigen Klammern sollen mit ihrem Wert*1000 ersetzt werden
$p = "(\[\d+\])" ; Search-Pattern
$sRet = _StrReplaceIterated($s, $p, '_GetManipulatedMatch') ; Funktionsaufruf mit Angabe der Funktion zur Manipulation der Matches
ConsoleWrite('Anzahl Ersetzungen:' & @extended & @LF)
ConsoleWrite($sRet & @LF)
Func _StrReplaceIterated($_s, $_sPatt, $_sReplFunc)
Local $aMatch, $iOff = 1, $sMatch = '', $sOff = '', $aPos, $sPart, $iStart = 1, $sOut = ''
While 1
$aMatch = StringRegExp($_s, $_sPatt, 1, $iOff)
If Not @error Then
$iOff = @extended
$sMatch &= $aMatch[0] & Chr(0)
$sOff &= $iOff & ','
Else
ExitLoop
EndIf
WEnd
If $sOff <> '' Then
$aPos = StringSplit(StringTrimRight($sOff, 1), ',')
$aMatch = StringSplit(StringTrimRight($sMatch, 1), Chr(0))
EndIf
If Not IsArray($aPos) Then Return SetError(1,0,0)
For $i = 1 To $aPos[0]
$sPart = StringTrimRight( StringMid($_s, $iStart, $aPos[$i]-$iStart), StringLen($aMatch[$i]) )
$sOut &= $sPart & Call($_sReplFunc, $aMatch[$i])
$iStart = $aPos[$i]
Next
$sOut &= StringRight($_s, StringLen($_s)-$aPos[$aPos[0]])
Return SetError(0, $aPos[0], $sOut)
EndFunc ;==> _StrReplaceIterated
; Funktion zur Manipulation der Matches
Func _GetManipulatedMatch($_s)
Local $i = StringTrimRight(StringTrimLeft($_s, 1), 1) *1000
Return "[" & $i & "]"
EndFunc