CSV-Datei in ein Array einlesen

  • Ich versuche gerade mit AutoIt eine CSV-Datei in ein Array einzulesen, finde aber nicht den richtigen Ansatz.
    In der Funktion StringSplit kann ich zwar das verwendete Trennzeichen angeben, aber in diesem Fall ist es eben kein ordinäres Komma oder was anderes darstellbares, sondern ein Tab (HT).
    Wie geb ich der Funktion zu verstehen, dass sie gefälligst damit arbeiten soll?

    Einmal editiert, zuletzt von UnKrauT_37 (5. Mai 2011 um 21:30)

  • Normalerweise sind csv Dateien ja mit ; getrennt. Sollte das bei dir nicht so sein kannst du auch @Tab verwende um mit Stringsplit die Spalten zu erhalten.
    Am besten postes du mal eine Beispieldatei, dann geht es am schnellsten ;)

  • Hallo ,

    herzlich willkommen im Forum und viel Spass mit AutoIt.

    Hier kannst du dir die deutsche Hilfe herunterladen.
    Hier gibt es ein AutoIt-Tutorial: http://wiki.autoit.de/wiki/index.php/TutorialSehr hilfreich ist auch das Buch von peethebee

    und jetzt zu deiner Frage du kannst Chr(9) nehmen um es zu splitten.

    [autoit]

    #include <Array.au3>
    $sTest ="Dies ist die 1.Zeile eines Tests."
    $aSplit = StringSplit($sTest,Chr(9))
    _ArrayDisplay($aSplit)

    [/autoit]

    oder das Makro @Tab

    [autoit]

    #include <Array.au3>
    $sTest ="Dies ist die 1.Zeile eines Tests."
    $aSplit = StringSplit($sTest,@TAB)
    _ArrayDisplay($aSplit)

    [/autoit]

    wie Schnitzel schon vorschlug,

    mfg autoBert

  • Probiere es mal damit:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    $file = FileOpenDialog("Select a CSV file", "", "File (*.csv)")
    If @error Then Exit
    $csv = FileRead($file)
    $aCSV = StringSplitW($csv, ";")
    _ArrayDisplay($aCSV)

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

    ; #FUNCTION# ========================================================================================================================================
    ; Name ................: StringSplitW()
    ; Version .............: v0.92 build 2013-03-25 beta
    ; Description .......: Splits a string into columns instead of rows as it is done by SplitString(), like a csv file to a 2d array ;)
    ; Syntax ..............: StringSplitW($sString, $sDelimiter, $iWidthLen)
    ; Parameters ........: $sString - string to split
    ; $sDelimiter - the delimter how to split the string
    ; $iWidthLen - length of the row (amount of columns - default is 100)
    ; Return values ....: Success - 2d array
    ; Error 1 - either $sString or $delimter is not set
    ; Error 2 - array width exceeded
    ; Error 3 - error splitting string
    ;
    ; Author ..............: UEZ
    ; Modified ............:
    ; Remarks ............:
    ; Related ..............: StringSplit()
    ; ===================================================================================================================================================
    Func StringSplitW($sString, $sDelimiter = ";", $iWidthLen = 256)
    If $sString = "" Or $sDelimiter = "" Then Return SetError(1, 0, 0)
    Local $chk, $iWidth, $i, $j, $k, $iLen, $iMax = 1, $iMaxWidth
    Local $aPos[1], $l = 0
    Local $aSplit = StringSplit($sString, @LF)
    If @error Then Return SetError(3, 0, 0)
    Local $aVertical[$aSplit[0]][$iWidthLen], $iDelimiterLen = StringLen($sDelimiter) - 1
    For $k = 1 To $aSplit[0]
    $iLen = StringLen($aSplit[$k])
    If $iLen > 1 Then
    $chk = StringReplace($aSplit[$k], $sDelimiter, $sDelimiter)
    $iWidth = @extended
    If $iWidth > $iWidthLen Then Return SetError(2, 0, 0)
    If $iWidth >= $iMax Then $iMax = $iWidth + 1
    Switch $iWidth
    Case 0
    $aVertical[$l][0] = $aSplit[$k]
    Case Else
    Dim $aPos[$iWidth * 2 + 2]
    $j = 1
    $aPos[0] = 1
    For $i = 0 To $iWidth - 1
    $aPos[$j] = StringInStr($aSplit[$k], $sDelimiter, 0, $i + 1) - 1
    $aPos[$j + 1] = $aPos[$j] + 2 + $iDelimiterLen
    $j += 2
    Next
    $aPos[UBound($aPos) - 1] = StringLen($aSplit[$k])
    $j = 0
    For $i = 0 To UBound($aPos) - 1 Step 2
    $aVertical[$l][$j] = StringMid($aSplit[$k], $aPos[$i], $aPos[$i + 1] - $aPos[$i] + 1)
    $j += 1
    Next
    EndSwitch
    $l += 1
    EndIf
    Next
    ReDim $aVertical[$l][$iMax]
    Return $aVertical
    EndFunc

    [/autoit]

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    4 Mal editiert, zuletzt von UEZ (10. April 2013 um 15:53)

  • Die Formulierung Chr(9) war es, die ich nirgendwo finden konnte. In den Beispielen in der Hilfe gibt es immer nur die Form ",".
    Ich bedanke mich herzlich.

    Gruß
    UnKrauT_37

  • Soweit so gut, das mit dem @TAB funktioniert so.
    Jetzt habe ich das nächste Problem:
    Ich versuche die bewusste csv in ein zweidimensionales Array einzulesen.

    [autoit]


    For $i = 1 To _FileCountLines ($file)
    $var=FileReadLine ($file,$i)
    $zArtikel=StringSplit ($var, @TAB)
    For $j =1 To $zArtikel [0]
    $Artikel [$j][$i] = $zArtikel [$j]
    Next
    Next

    [/autoit]

    Die Aufteilung der Elemente funktioniert, in $zArtikel [0] steht lt. Hilfe die Anzahl der Zeilen-Elemente, die an $j übergeben wird. Die Zuweisung an das Array $Artikel[$j][$i] wird mit einer Laufzeit-Fehlermeldung quittiert.
    In $zArtikel[$j] ist der richtige Wert enthalten, dazu habe ich die zweite Schleife auskommentiert und über eine MsgBox den Inhalt anzeigen lassen.
    Wo liegt mein Denkfehler?

    UEZ
    Bei deiner Funktion verweigert AutoIt bei mir die Ausführung in der Zeile 29 und bemängelt [$max_width]. Die Variable hat aber zu der Zeit den zugewiesenen Wert 0x7fff (32767)

    Gruss an alle
    UnKrauT_37

  • Eine Lösung gibt es schon, aber nach meiner Empfindung passt die nicht zum Problem.

    Ich gebe ja das Trennzeichen explizit an (@TAB) und vermeide damit (hoffentlich) den Versuch, das Trennzeichen automatisch erkennen zu wollen.

    Gruss
    UnKrauT_37

  • Hmm, ich kenne deine Datei nicht und auch nicht, wie du die Funktion aufrufst! Wie ist denn die genaue Fehlermeldung?

    Hier ein Beispiel mit Tabs getrennte Zeilen:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>

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

    Global $gs_dummydata = ""
    $gs_dummydata &= "john" & @TAB & "smith" & @TAB & "12345" & @CRLF
    $gs_dummydata &= "josh" & @TAB & "jones" & @TAB & "34556" & @TAB & "supervisor" & @CRLF
    $gs_dummydata &= "" & @CRLF ; empty line
    $gs_dummydata &= "zach" & @TAB & "marks" & @TAB & "98222" & @TAB & "worker" & @TAB & "extra column not expected" & @CRLF
    $gs_dummydata &= "jake" & @TAB & "warren" & @TAB & "10984" & @TAB & "worker" & @CRLF ; (last line will actually be empty because of CRLF)
    ;~ $gs_dummydata = 'john,smith,12345,"happy",manager,,"abra,ca,da,br,a"'
    MsgBox(0, "Test", $gs_dummydata)
    Global $aS = StringSplitW($gs_dummydata, @TAB)
    _ArrayDisplay($aS)
    Exit

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

    ; #FUNCTION# ========================================================================================================================================
    ; Name ................: StringSplitW()
    ; Version .............: v0.92 build 2013-03-25 beta
    ; Description .......: Splits a string into columns instead of rows as it is done by SplitString(), like a csv file to a 2d array ;)
    ; Syntax ..............: StringSplitW($sString, $sDelimiter, $iWidthLen)
    ; Parameters ........: $sString - string to split
    ; $sDelimiter - the delimter how to split the string
    ; $iWidthLen - length of the row (amount of columns - default is 100)
    ; Return values ....: Success - 2d array
    ; Error 1 - either $sString or $delimter is not set
    ; Error 2 - array width exceeded
    ; Error 3 - error splitting string
    ;
    ; Author ..............: UEZ
    ; Modified ............:
    ; Remarks ............:
    ; Related ..............: StringSplit()
    ; ===================================================================================================================================================
    Func StringSplitW($sString, $sDelimiter = ";", $iWidthLen = 256)
    If $sString = "" Or $sDelimiter = "" Then Return SetError(1, 0, 0)
    Local $chk, $iWidth, $i, $j, $k, $iLen, $iMax = 1, $iMaxWidth
    Local $aPos[1], $l = 0
    Local $aSplit = StringSplit($sString, @LF)
    If @error Then Return SetError(3, 0, 0)
    Local $aVertical[$aSplit[0]][$iWidthLen], $iDelimiterLen = StringLen($sDelimiter) - 1
    For $k = 1 To $aSplit[0]
    $iLen = StringLen($aSplit[$k])
    If $iLen > 1 Then
    $chk = StringReplace($aSplit[$k], $sDelimiter, $sDelimiter)
    $iWidth = @extended
    If $iWidth > $iWidthLen Then Return SetError(2, 0, 0)
    If $iWidth >= $iMax Then $iMax = $iWidth + 1
    Switch $iWidth
    Case 0
    $aVertical[$l][0] = $aSplit[$k]
    Case Else
    Dim $aPos[$iWidth * 2 + 2]
    $j = 1
    $aPos[0] = 1
    For $i = 0 To $iWidth - 1
    $aPos[$j] = StringInStr($aSplit[$k], $sDelimiter, 0, $i + 1) - 1
    $aPos[$j + 1] = $aPos[$j] + 2 + $iDelimiterLen
    $j += 2
    Next
    $aPos[UBound($aPos) - 1] = StringLen($aSplit[$k])
    $j = 0
    For $i = 0 To UBound($aPos) - 1 Step 2
    $aVertical[$l][$j] = StringMid($aSplit[$k], $aPos[$i], $aPos[$i + 1] - $aPos[$i] + 1)
    $j += 1
    Next
    EndSwitch
    $l += 1
    EndIf
    Next
    ReDim $aVertical[$l][$iMax]
    Return $aVertical
    EndFunc

    [/autoit]

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    4 Mal editiert, zuletzt von UEZ (10. April 2013 um 17:07)

  • Insgesamt hat die Datei 3048 Zeilen mit jeweils 6 Elementen.
    Einen Auszug hab ich mal angehängt.
    Es muss etwas mit der genannten Variablen $max_width zu tun haben, denn einen Auszug aus meiner Datei mit 3 Zeilen kann ich problemlos einlesen.
    Auch wenn ich die Variable auf 0xFFFF setze, wird abgebrochen.
    Die Fehlermeldung ist für mich nichtssagend:

    Local $aVertical[$aSplit[0]][$max_width]
    Local $aVertical[$aSplit[0]][^ ERROR

    Gruss
    UnKrauT_37

  • Da habe ich mit dem max. Wert wohl geirrt! Ersetze mal $max_width mit $max_width = 0x058D

    Ich versuche gerade den Zusammenhang der möglichen Gesamtgröße eines 2D Array herauszufinden! 0x058D funktioniert auch nur bis zu einer bestimmten Dateigröße!

    In deinem Fall reicht es, wenn du $max_width = 0x0F setzt.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    Einmal editiert, zuletzt von UEZ (5. Mai 2011 um 12:32)

  • Anscheinend darf die Höhe + Breite eines 2D Arrays nicht größer als 0x5EFA sein.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Nächstes Problem:

    In deiner Split-Routine schliesst du den Fall aus, dass das erste Zeichen leer ist (Zeile 41).

    Bei mir kann aber der Fall eintreten, dass das erste Feld mit einem leeren Wert gefüllt ist, der Fall darf also nicht ausgeschlossen werden. Das einfache Auskommentieren der If ... EndIf Anweisung bringt keinen Erfolg.
    Wo kann/muss ich schrauben?

    edit
    Denkfehler meinerseits. Bei meinem Versuch hatte ich die Maximale Dimensionierung falsch angegeben.
    Deine Routine macht genau das, was sie soll.
    /edit

    Gruss
    UnKrauT_37

    Einmal editiert, zuletzt von UnKrauT_37 (5. Mai 2011 um 13:29)

  • Ich habe den Code von StringSplitW() aktualisiert; den $max_width habe ich entfernt, wird jetzt berechnet.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯