Suche Workaround RegExp Repeating Character Pattern Limit

  • [autoit]

    #include <Array.au3>

    [/autoit][autoit][/autoit][autoit][/autoit][autoit]

    $sString = "[abc],[def],[ghijklm],[nopq],[r],[s],[tuvwx],[yz],[12345],[6789],[10]"
    $iMaxLen = 15

    [/autoit][autoit][/autoit][autoit]

    $aStringRegExp = StringRegExp($sString, "\[.{1," & $iMaxLen - 2 & "}\],??", 3)

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($aStringRegExp)

    [/autoit][autoit][/autoit][autoit]

    $iMaxLen = 65537+1 ; hier is die grenze bzw. bei 65535

    [/autoit][autoit][/autoit][autoit]

    $aStringRegExp = StringRegExp($sString, "\[.{1," & $iMaxLen - 2 & "}\],??", 3)

    [/autoit][autoit][/autoit][autoit]

    _ArrayDisplay($aStringRegExp)

    [/autoit]

    Mein Idee war dem Pattern "." irgendwie zu ersetzten mit einem Pattern der auch für alle Zeichne steht aber gleich mehrere Zeichen erzwingt.

    Also "." durch ".{10}" ersetzen dann könnte ich $iMaxLen 10 x kleiner machen.
    aus
    "\[.{1," & $iMaxLen - 2 & "}\],??"
    wird
    "\[.{10}{1," & $iMaxLen - 2 & "}\],??"
    Leider funktioniert das verschachteln von Pattern so nicht.

    Einmal editiert, zuletzt von BiNu (2. Februar 2014 um 22:40)

  • Den String splitten mit der Möglichkeit die maximale Anzahl Zeichen für die Stücke anzugeben.
    Dabei darf der String nur an bestimmten Stellen geteilt werden damit die Stückchen nicht unbrauchbar werden.
    Es darf also nur bei , geteilt werden.
    Der echte spring ist tausende Zeichen lang deshalb der Beispiel String zum zeigen wie der zusammengesetzt ist.

    Es soll also genau dass machen was es tut nur eben mit mehr Zeichen.

    • Offizieller Beitrag

    So richtig kann ich dir nicht folgen.
    Du hast einen String, tausende Zeichen lang mit Gruppen von"[irgendwas]" getrennt durch Kommata - richtig?
    Und was ist jetzt der Knackpunkt, was macht es unmöglich den Teil zwischen den Klammern abzufragen? Ich sehe da kein Hindernis.

  • Dann teil doch bei jedem Komma

    [autoit]

    "\[.+?\]"

    [/autoit]


    und setze die einzelnen Teilstücke nach belieben wieder zusammen.

    Dann muss ich den String zuerst in hunderte Stücke teilen danach wieder aneinander reihen und bei jedem hinzugefügten Stück die Gesamtlänge mit der gewünschten Maximallänge vergleichen und wenn überschritten wider ein Stück weg nehmen. Und das so lange bis keine Stücke mehr da sind :wacko:

    So richtig kann ich dir nicht folgen.
    Du hast einen String, tausende Zeichen lang mit Gruppen von"[irgendwas]" getrennt durch Kommata - richtig?
    Und was ist jetzt der Knackpunkt, was macht es unmöglich den Teil zwischen den Klammern abzufragen? Ich sehe da kein Hindernis.

    Richtig soweit. Der Knackpunkt ist dass ich möglichst viele dieser [irgendwas] aneinander haben will aber nicht mehr Zeichen als angeben als $iMaxLen

    • Offizieller Beitrag

    Alternativvariante:
    - Lösche alle "[" "]" und ","
    - übrig bleibt der gewünschte Inhalt
    - jetzt häckseln in Teile fester Länge

    [autoit]


    $s = StringRegExpReplace("DEIN_STRING", "[\[\],]", "")
    $aMatch = StringRegExp($s, ".{1, " & $iMaxLen & "}", 3)

    [/autoit]
  • in der vollständigen beschreibung der PCRE Pattern steht was den fehlschlag erklärt wen die 2 zahl größer ist.

    Zitat

    The general repetition quantifier specifies a minimum and maximum number of permitted matches, by giving the two numbers in curly brackets (braces), separated by a comma. The numbers must be less than 65536, and the first must be less than or equal to the second


    ich würde die Maximalanzahl der Zeichen so umgehen das ich einfach 2x den Ausdruck hintereinander verwende. Ceiling und Floor müssten die .5 bei ungeraden Zahlen beheben. (ungetestet)

    [autoit]

    StringRegExp($string ,"\[.{1,"&Ceiling($MaxLen/2)&"}.{1,"&Floor($MaxLen/2)&"}\],??",3)

    [/autoit]


    natürlich

  • Alternativvariante:
    - Lösche alle "[" "]" und ","
    - übrig bleibt der gewünschte Inhalt
    - jetzt häckseln in Teile fester Länge

    [autoit]


    $s = StringRegExpReplace("DEIN_STRING", "[\[\],]", "")
    $aMatch = StringRegExp($s, ".{1, " & $iMaxLen & "}", 3)

    [/autoit]


    8|
    Erstens bleibt hier das Limit genau gleich $iMaxLen kann auch hier nicht grösser als ~65500 sein.
    Zweites wird dadurch doch auch innerhalb von [] geteilt bzw. es wird alles aneinander gehängt und eine Trennung nur beim Koma ist nicht mehr möglich.
    Das Problem ist dass $iMaxLen nicht grösser sein kann. Der Patter in meinem Beispiel würde sonst genau das machen was er soll.

    Nochmals zur Aufgabe.
    Der String enthält viele Teilstrings unterschiedlicher Länge welche erhalten bleiben müssen.
    Es darf also nur beim Komma getrennt werden.
    Es soll nach so vielen Teilstrings getrennt werden dass der String möglichst genau die Länge $iMaxLen hat.

    Bsp.

    String: "Teilstring,Nocheiner,Ich-bin-ein-Teilstring-und-muss-zusammen-beliben,Ich-bin-das-auch-aber-kürzer,ich-auch-sogar-mit-z4hlen,blablabla,loremipsum,usw und so fort"

    Maxlen = 25
    Also trennen nach 25 zeichen
    "Teilstring,Nocheiner,Ich-bin-ein-Teilstring-und-muss-zusammen-beliben,.....

    Aber halt da darf nicht getrennt werden also trenne beim vorherigen Komma.

    "Teilstring,Nocheiner,Ich-bin-ein-Teilstring-und-muss-zusammen-beliben,....

    Also das Grüne im Array speichern und mit dem übrigen String das Gleiche mach so lange bis nichts mehr übrig ist.
    MaxLen ist dabei immer länger als der längste Teilstring so das sicher jeder Teilsting verarbeitet wird.

    in der vollständigen beschreibung der PCRE Pattern steht was den fehlschlag erklärt wen die 2 zahl größer ist.


    ich würde die Maximalanzahl der Zeichen so umgehen das ich einfach 2x den Ausdruck hintereinander verwende. Ceiling und Floor müssten die .5 bei ungeraden Zahlen beheben. (ungetestet)

    [autoit]

    StringRegExp($string ,"\[.{1,"&Ceiling($MaxLen/2)&"}.{1,"&Floor($MaxLen/2)&"}\],??",3)

    [/autoit]


    natürlich

    Genau das Limit ist das Problem dass steht da schon im ersten Post seit immer^^.
    Der Pattern einfach zu wiederholen macht leider nicht das selbe.
    Zwischen MaxLen und der tatsächlichen Länge gibt ja mit sehr grosser Wahrscheinlichkeit einen Unterschied. Der String ist zu 99% ein bisschen kürzer. Diese Differenz summiert sich bei verdoppeln des Patterns logischerweise. Die Differenz kann also zusammen länger sein als der nächste Teilstring.
    Zudem müsste ich den Pattern nicht doppelt haben sonder eher 10-30 mal damit ich zuverlässig die 65000 Limit nicht überschreite.
    Auch müsste man die wiederholten Pattern noch optional machen denn der letzte String kann ja aus nur einem Teilstring bestehen und würde bei doppeltem oder gar 10 fachem Pattern dann kein Mach mehr geben.

    Das genau gleiche würde ich erreichen indem ich MaxLen halbieren und jeweils 2 Stringes wieder zusammen hänge. Damit gäbe es auch kein Problem wenn am Schluss nur ein Teilstring übrig ist. Die Abweichung summiert sich jedoch auch bei dieser Variante und bei 10-30 mal macht das schon was aus.

    Aber es sieht wohl so aus also ob es keine andere Möglichkeit gibt. Jede Programmiersprache hat seine Grenzen. Bei AutoIt sind sie leider manchmal schnell erreicht. Aber gut kann man Arrays mit 64 Dimensionen machen :rofl: .

    Weitere Lösungen oder Tims sind natürlich erwünscht.

    • Offizieller Beitrag

    Hast du mal so eine Musterdatei?
    Ich könnte probieren, ob das mit Lua realisierbar ist. Ich habe ja eine UDF zur Verwendung von Lua-Inline in AutoIt erstellt. Ich kann aber vorab nicht sagen ob das Pushen solch großer Datenmengen auf den Lua Stack anstandslos funktioniert.

  • Hab mich noch nie mit Lua befasst. Ob ich dass in meinem Script verwenden könnte kann ich also nicht sagen.
    Wenn du trotzdem ausprobieren willst interessant wäre es jedenfalls =).

    Echte Daten hab ich hier keine und wäre auch nicht wirklich geeignet zum Posten. Aber der Inhalt Ist Text also deutsche Zeichen wie in der Zeitung.

    Getestet hab ich damit. dass erzeugt ein vergleichbaren String.
    ca. 830'000 Zeichen lang. Also nur ~800 KB. Sind für heutige Verhältnis gar keine gossen Datenmengen die 65'000 Limit ist einfach mager.
    Dauert auf meinem i7 ca. 30 Sekunden und 60 MB RAM zu generieren.

    [autoit]

    #include <Crypt.au3>

    [/autoit][autoit][/autoit][autoit]

    $String = ""
    For $i = 0 To 10000
    $Random = Hex(_Crypt_HashData(Random(0, 999999999999), $CALG_MD5))
    $Random = StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 31, 1))
    $String &= "[" & $Random & "],"
    Next
    ConsoleWrite($String & @CRLF)
    ConsoleWrite(StringLen($String) & @CRLF)

    [/autoit][autoit][/autoit][autoit]

    Exit

    [/autoit]
    • Offizieller Beitrag

    Habs dann doch noch gleich fertiggestellt, geht tadellos und schwuppdifix ;)
    Du brauchst die angehängten Includes dafür.

    [autoit]


    #include "LuaInline.au3"
    _Lua_StartUp() ; == Initialisiert Lua, Shutdown automatisch bei AutoIt-Ende

    [/autoit][autoit][/autoit][autoit]

    Global $sLua = _
    " local pathStr = 'C:\\Code_AutoIt\\TEST\\String.txt'" & _ ; == Dateipfad zum Einlesen
    " local pathOut = 'C:\\Code_AutoIt\\TEST\\Separated.txt'" & _ ; == Dateipfad für Ergebnis (jede Zeile ein Wert)
    " local fh = io.open(pathStr)" & _
    " local sString = fh:read()" & _
    " fh:close()" & _
    " " & _
    " local iMax = 80000" & _ ; <<<<<< Hier die Max Länge angeben <<<<<<<<
    " local sTmp, tResult = '', {}" & _
    " " & _
    " local Merge = function(_v)" & _
    " if _v == nil then" & _
    " tResult[#tResult+1] = sTmp" & _
    " elseif (#_v + #sTmp) > iMax then" & _
    " tResult[#tResult+1] = sTmp" & _
    " sTmp = _v" & _
    " else" & _
    " sTmp = sTmp.._v" & _
    " end" & _
    " end" & _
    " " & _
    " for v in sString:gmatch('(%b[])') do" & _
    " v = v:gsub('[%[%]]', '')" & _
    " Merge(v)" & _
    " end" & _
    " Merge()" & _
    " " & _
    " local sWrite = ''" & _
    " for i = 1, #tResult do" & _
    " sWrite = sWrite..tResult[i]..'\n'" & _
    " end" & _
    " fh = io.open(pathOut, 'w+')" & _
    " fh:write(sWrite)" & _
    " fh:close()"

    [/autoit][autoit][/autoit][autoit]

    _Lua_DoString($sLua)

    [/autoit][autoit][/autoit][autoit]

    ConsoleWrite('FERTIG !' & @LF)

    [/autoit]

    Edit:
    Du wolltest das unbedingt in ein Pattern pressen, das ist aber der Aufgabe schlicht und einfach nicht angemessen. Ein generisches Abarbeiten der Matches ist hier effektiver.

    Das generische Bearbeiten, wie ich es dort in Lua gemacht habe, läßt sich aber auch in AutoIt per Callback-Funktion erledigen. Und ist (zumindest bei der Dateigröße von 800 kb) nicht spürbar langsamer als in Lua. Bei größeren Dateien könnte die Speed von Lua spürbar werden.

    AutoIt-Variante:

    [autoit]

    $pathStr = 'C:\Code_AutoIt\TEST\String.txt'
    $pathOut = 'C:\Code_AutoIt\TEST\Separated.txt'
    $sString = FileRead($pathStr)
    $iMax = 80000
    Global $sMatch, $sTmp

    [/autoit][autoit][/autoit][autoit]

    _StringRegExpReplace_Callback($sString, "(\[.+?\])", "__CallBack_Match('\1')")
    __CallBack_Match() ; letzten Inhalt von $sTmp noch anfügen

    [/autoit][autoit][/autoit][autoit]

    ;~ ConsoleWrite($sMatch & @LF)
    FileWrite($pathOut, $sMatch)

    [/autoit][autoit][/autoit][autoit]

    Func __CallBack_Match($s='')
    $s = StringRegExpReplace($s, '[\[\]]', '')
    If $s = '' Then
    $sMatch &= @CRLF & $sTmp
    ElseIf (StringLen($sTmp) + StringLen($s)) > $iMax Then
    $sMatch &= @CRLF & $sTmp
    $sTmp = $s
    Else
    $sTmp &= $s
    EndIf
    EndFunc

    [/autoit][autoit][/autoit][autoit]

    ; #FUNCTION# ====================================================================================================================
    ; Name ..........: _StringRegExpReplace_Callback
    ; Description ...:
    ; Syntax ........: _StringRegExpReplace_Callback($sString, $sPattern, $sCallback[, $sBefore = ''[, $sAfter = '']])
    ; Parameters ....: $sString
    ; $sPattern
    ; $sCallback
    ; $sBefore
    ; $sAfter
    ; Return values .: None
    ; Author ........: Taz77 (Markus Ehmig <autoit at ehmig dot net>)
    ; Since .........: 2012/04/23
    ; Modified ......: 2013/05/11
    ; Remarks .......: Achtung! Das ' wird temporär im $sString durch \x1a ersetzt, wenn im plattern danach gesucht werden soll, muss nach \x1a enstelle von ' gesucht werden
    ; Related .......:
    ; Link ..........:
    ; Example .......: No
    ; ===============================================================================================================================
    Func _StringRegExpReplace_Callback($sString, $sPattern, $sCallback, $sBefore='', $sAfter='')
    Local $Str = Execute("'" & StringRegExpReplace(StringReplace($sString, "'", Chr(26), 0, 2), $sPattern, $sBefore&"'&" & $sCallback & "&'"&$sAfter) & "'")
    If @error then
    ConsoleWrite('_StringRegExpReplace_Callback error! Pattern: "'&$sPattern&'", Callback: "'&$sCallback&'"' & @LF)
    Return $sString
    EndIf
    Return StringReplace($Str, Chr(26), "'", 0, 2)
    EndFunc

    [/autoit]
  • Sicherlich hab ich es falsch verstanden - aber vielleicht könnt ihr ja nochmal erklären was ich nun genau nicht verstanden habe:

    [autoit]

    Global CONST $D_MAXLEN = 50
    Global $s_String = "Teilstring,Nocheiner,Ich-bin-ein-Teilstring-und-muss-zusammen-beliben,Ich-bin-das-auch-aber-kürzer,ich-auch-sogar-mit-z4hlen,blablabla,loremipsum,usw und so fort"

    [/autoit][autoit][/autoit][autoit]

    For $i in StringRegExp($s_String, "(.{1," & $D_MAXLEN & "}),", 3)
    ConsoleWrite($i & @CRLF)
    Next

    [/autoit]
  • Ok - und so?:

    String in möglichgst gleichgroße Teile splitten
    [autoit]

    #include <Crypt.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global Const $D_MAXLEN = 150 ; Maximale Länge eines Teilstrings
    Global $s_OutPath = @DesktopDir & "\Test.txt" ; Pfad zur Ausgabedatei

    [/autoit] [autoit][/autoit] [autoit]

    Global $s_String = "", $i_BlockStart, $i_BlockEnd, $s_SubString, $h_File, $d_MaxPos

    [/autoit] [autoit][/autoit] [autoit]

    #Region Teststring erzeugen
    For $i = 0 To 10000
    $Random = Hex(_Crypt_HashData(Random(0, 999999999999), $CALG_MD5))
    $Random = StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 32, 1)) & StringTrimLeft($Random, Random(0, 31, 1))
    $s_String &= "[" & $Random & "],"
    Next
    $d_MaxPos = StringLen($s_String)
    ConsoleWrite($d_MaxPos & @CRLF)
    #EndRegion Teststring erzeugen

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    #Region Datei splitten und in Ausgabedatei ausgeben
    $h_File = FileOpen($s_OutPath, 2)

    [/autoit] [autoit][/autoit] [autoit]

    $i_BlockStart = 1
    $i_BlockEnd = $D_MAXLEN
    While $i_BlockStart <= $d_MaxPos
    $i_BlockEnd = $i_BlockEnd >= $d_MaxPos ? $d_MaxPos : StringInStr($s_String, ",", 1, -1, $i_BlockEnd)
    $s_SubString = StringMid($s_String, $i_BlockStart, $i_BlockEnd - $i_BlockStart)

    [/autoit] [autoit][/autoit] [autoit]

    If $i_BlockEnd = ($i_BlockStart - 1) Then
    SetError(1)
    ExitLoop
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    FileWriteLine($h_File, $s_SubString)

    [/autoit] [autoit][/autoit] [autoit]

    $i_BlockStart = $i_BlockEnd + 1
    $i_BlockEnd = $i_BlockStart + $D_MAXLEN
    WEnd
    If @error Then MsgBox(48, "Fehler", "$D_MAXLEN kleiner als längster Teilstring!")
    FileClose($h_File & @CRLF)
    #EndRegion Datei splitten und in Ausgabedatei ausgeben

    [/autoit]

    Einmal editiert, zuletzt von AspirinJunkie (31. Januar 2014 um 10:14)