Zugriff auf Zeichen im String

  • AutoIt ist so eine feine Sprache. Gibt es wirklich keine Möglichkeit, direkt auf ein Zeichen in einem String zuzugreifen?

    So wie bei C++ : string[x].

    Muss man immer über zeitaufwendige Funktionen (StringMid usw.) gehen?

    Einmal editiert, zuletzt von DOheim (27. November 2013 um 10:14)

  • in wiefern zeitaufwändig?

    kannst dir ja eine eigene funktion bauen, in etwa:

    string($str,$cnt)
    string("test",2) = e

    is doch kein problem ;)

    Simon nörgelt, Simon nervt - aber Simon verbessert die Welt. Glaubt er.

  • Du kannst besagte Bitmap-Datei in einer Struct (char/wchar/etc[x]) speichern und mittels DllStructGet-/SetData auf die einzelnen Elemente zugreifen.

  • [autoit]

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

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

    Global $cStr = StrToCStr('Make-Grafik')
    Global $i

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

    For $i = 1 To CStrLen($cStr)
    MsgBox(262144, 'Example', CStrChar($cStr, $i))
    Next

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

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

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

    Func StrToCStr($sString)
    Local $iLen = StringLen($sString)
    Local $tStruct = DllStructCreate('char[' & $iLen & ']; int')

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

    DllStructSetData($tStruct, 1, $sString)
    DllStructSetData($tStruct, 2, $iLen)
    Return $tStruct
    EndFunc

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

    Func CStrChar(ByRef $tStruct, $iIndex)
    Return DllStructGetData($tStruct, 1, $iIndex)
    EndFunc

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

    Func CStrLen(ByRef $tStruct)
    Return DllStructGetData($tStruct, 2)
    EndFunc

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

    ; ++++++++++ +++++++++ ++++++++ +++++++ ++++++ +++++ ++++ +++ ++ +

    [/autoit]
  • Wenns allein um die Syntax geht kannst du einen String in AutoIt auch in ein zeichenweises Array konvertieren.

    Hier mal ein Beispiel:

    [autoit]

    #include "Array.au3"

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

    Global Const $s_String = "Hallo Welt"

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

    Global $a_ASCII = StringToASCIIArray($s_String)
    _ArrayDisplay($a_ASCII, "ASCII-Array")

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

    Global $a_Chars = StringSplit($s_String, "", 2)
    _ArrayDisplay($a_Chars, "Char-Array")

    [/autoit]

    Wenn ich z.B. eine Bitmap-Datei, die aus 20 MByte besteht, bearbeiten möchte und dort Millionen von Zeichen austausche will, dann dauert das ewig.

    Bitmaps solltest du nicht als Zeichenkette verarbeiten.
    Nutz stattdessen die DllStructs.
    Aber auch da ist zu sagen: Dafür ist AutoIt schlicht nicht gemacht - wirklich performant wirst du es mit AutoIt alleine nicht hinbekommen.

  • Zitat

    Wenn ich z.B. eine Bitmap-Datei, die aus 20 MByte besteht, bearbeiten möchte und dort Millionen von Zeichen austausche will, dann dauert das ewig.

    Sagt wer?
    Na dann zeig mal dein Script, was so "ewig" dauert...
    Guckst du:

    Spoiler anzeigen
    [autoit]

    $a = ""
    for $i = 32 to 132 ;100 Byte "Paket" erstellen, "Fixed Length Block"
    $a &= Chr($i)
    next

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

    for $i = 1 to 18 ;bissl spielen von 10-20
    $a &= $a
    next

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

    ConsoleWrite(Int(StringLen($a) / 1e6) & "MB" & @crlf)

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

    $t=timerinit()
    $b=stringreplace($a,"ABC","XXX",0,1)
    $anz=@extended
    consolewrite("Innerhalb von " & stringformat("%.3f",timerdiff($t)/1000) & "Sekunden wurden in "&stringlen($a)& " Bytes genau " & $anz &" Ersetzungen durchgeführt." & @crlf)

    [/autoit]


    tauscht auf meinem langsamen Gurkenrechner in 180ms innerhalb von 26MB genau 262144x ABC in XXX, also genau das, was ein "Pixelumschreiber" für RGB-Daten auch machen würde.
    Also 1,3MB Daten tauschen pro Sekunde...dauert ewig?!

  • In Kombination Eurer umfangreichen Anregungen habe ich folgendes Programm geschrieben:

    [autoit]


    #include "HilfsFunktionen.au3"
    Global $Protokoll1=2 ; =2, dann wird protokolliert
    ; =0, dann wird nicht protokolliert
    $ProgrammName="Test1" ; für Protokoll
    ;-------------------------------------------------------------------------
    Protokoll("Anfang")
    $datei="d:\arbdat\Alarmanlage 2a.bmp"
    $handl=FileOpen ($datei)
    $feld=FileRead ( $handl)
    $anz=@extended
    FileClose ( $handl)
    Local $a = StringToASCIIArray($feld)
    Protokoll("Anzahl:"&$anz)
    For $i=0 To $anz-2
    $a[$i]=$a[$i+1]
    Next
    Protokoll("AAAA")
    Local $s = StringFromASCIIArray($a)
    Protokoll("BBBB")
    $handl=FileOpen("d:\arbdat\Alarm.bmp",2)
    FileWrite ($handl,$s)
    FileClose ( $handl)
    Protokoll("Ende")

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

    Das Protokoll sieht dann so aus:

    Programmname: Test1
    2013/11/27 09/53/39
    ..........Zeit(sec)
    Test1 0.000306 Anfang
    Test1 2.149016 Anzahl:6714366
    Test1 7.097853 AAAA
    Test1 7.886551 BBBB
    Test1 7.900876 Ende


    Das alles als nur in 8 Sekunden. Ihr könnt Euch vorstellen, dass ich jetzt höchst zufrieden bin.

    Ich danke Euch allen für Eure Mühe mit mir.

  • Wenn du nur einmal eine Datei ausliest und nur einmal schreibst reicht ein FileRead/Write mit Dateiname statt Handle aus.
    Im Hintergrund wird dann sowieso implizit FileOpen und FileClose ausgeführt.

    Sehe ich das aber richtig, dass du einfach nur alle Bytes jeweils um eine Position nach vorne verschieben willst?
    Wenn ja - dann solte folgendes einfacher und schneller gehen:

    [autoit]

    #include <Constants.au3>

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

    ; Alte Datei ohne erstes Byte einlesen:
    $h_File = FileOpen("Test.bmp", 16)
    FileSetPos($h_File, 1, $FILE_BEGIN)
    $b_File = FileRead($h_File)
    FileClose($h_File)

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

    ; Neue Datei schreiben:
    FileWrite("Test_out.bmp", $b_File)

    [/autoit]
  • Nein, das sollte nur zeigen, wie schnell es gehen würde, selbst wenn man alle 6,7 MByte Zeichen einzeln austauscht.
    Dein Hinweis auf die Funktion StringToASCIIArray war sehr wichtig, dadurch bin ich dann auch auf die erst recht wichtige Funktion StringFromASCIIArray aufmerksam geworden.
    Gruß
    Dieter

  • Hi,
    was hat denn ein StringToASCIIArray in einem Script zur Bearbeitung von Bitmaps zu suchen?
    Die Bitmap-Daten liegen bereits in einem Array, nämlich nacheinander im Speicher, zu adressieren über ihre Adresse oder x- und y-Koordinaten!
    Du liest also ein Array in ein anderes Array ein, läufst dann durch den Code um schlussendlich das Array wieder in ein Array zu schreiben?! Und eröffnest Threads mit dem Hinweis auf C++ und dessen "Geschwindigkeit?!

    Zitat

    So wie bei C++ : string[x].


    Mit Verlaub, programmiertechnisch hochgradigiger Dünnsch****. :thumbdown:
    Mittlerweile ist mir klar, wieso Software immer langsamer wird, wenn man mit der Aussage konfrontiert wird "muss schnell sein, ist doch in C++ geschrieben!"

    Wie schon von AspirinJunkie in Post 7 vorgeschlagen, lies die Bitmap in eine Struct ein, bearbeite dort deine "Pixel" bzw. Bereiche je nach Gusto, und wenn DANN Geschwindigkeit fehlt, schreibt man ggf eine Funktion in einigen Zeilen C als Dll, und ruft diese von AutoIt mit der Startadresse der Struct als Parameter auf.
    Beispiele für Bitmap-Be- und Verarbeitung gibt es reichlich hier im Forum, fast die Hälfte aller ASM-Scripte befassen sich mit Bitmaps, u.a. deswegen, weil deren Struktur so einfach ist.