CSV-Datei in 2D-Array einlesen / Problem: StringSplit()

  • Hallo,

    ich wollte eine CSV-Datei in ein zweidimensinales Array einlesen. Habe dazu bisher folgende Funktion geschrieben

    [autoit]

    Func CSVlesen($file) ;Liest den Inhalt der übegebebenen CSV-Datei in ein zweidimensionales Array und gibt dieses zurück (erstes Element enthält Anzahl Zeilen)
    Local $CountLines = _FileCountLines($file)
    Local $zeilen[$CountLines+1]
    Local $zeile
    $zeilen[0] = $CountLines
    $csv = FileOpen($file, 0)
    For $i = 1 To $CountLines
    $zeile = FileReadLine($csv)
    If @error = -1 Then
    ExitLoop
    EndIf
    MsgBox(64, "Test", "Inhalt: " & $zeile) ;hier wird die ganze Zeile korrekt ausgegeben.
    $zeilen[$i] = StringSplit($zeile, ";")
    MsgBox(64, "Test", "Inhalt: " & $zeilen[$i]) ;ist scheinbar leer
    MsgBox(64, "Test", "Inhalt: " & $zeilen[$i][0]) ;erzeugt Fehlermeldung!
    Next
    FileClose($csv)
    Return $zeilen
    EndFunc

    [/autoit]

    Leider gibts die folgende Fehlermeldung:
    ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
    MsgBox(64, "Test", "Inhalt: " & $zeilen[$i][0])
    MsgBox(64, "Test", "Inhalt: " & ^ ERROR

    Kann mir jemand verraten, woran das liegt?

    Einmal editiert, zuletzt von jans16 (20. Juli 2007 um 12:07)

  • Danke für die schnelle Antwort, aber daran liegt es nicht.
    Die Fehlermeldung entsteht schon beim ersten Durchlauf der For-Scheife in Zeile 15. Und ich schreibe ja extra
    Local $zeilen[$CountLines+1]
    um dann im ersten Element noch die Anzahl zu speichern.
    Wenn ich Zeile 15 deaktiviere, läuft die Funktion einwandfrei durch und gibt in Zeile 12 jeweils die gesamte Zeile korrekt aus.

    Einmal editiert, zuletzt von jans16 (20. Juli 2007 um 12:09)

  • Ich seh da jetzt nicht so das Problem:

    Spoiler anzeigen
    [autoit]

    #include <File.au3>

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

    _CVSRead("test.cvs")

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

    Func _CVSRead($s_file)
    Local $i_linecount = 0
    Local $h_file = -1
    Local $s_line = ""

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

    If FileExists($s_file) == 0 Then
    Return(0)
    EndIf

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

    $i_linecount = _FileCountLines($s_file)
    Local $a_rows[$i_linecount + 1]
    $a_rows[0] = $i_linecount

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

    $h_file = FileOpen($s_file, 0)

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

    For $i = 1 To $i_linecount - 1 Step 1
    $s_line = FileReadLine($h_file)
    If @error == -1 Then
    ExitLoop
    EndIf
    MsgBox(64, "Test", "Inhalt: " & $s_line)
    $a_rows[$i] = StringSplit($s_line, ";")
    MsgBox(64, "Test", "Inhalt: " & $a_rows[$i])
    MsgBox(64, "Test", "Inhalt: " & $a_rows[$i][0])
    Next
    FileClose($h_file)

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

    Return($i_linecount)
    EndFunc

    [/autoit]

    Was willst Du überhaupt genau erreichen? poste doch mal Deine CVS-Datei, wenn es geht...

    • Offizieller Beitrag

    HI,

    habe es so getestet, geht einwandfrei.

    [autoit]

    #include<File.au3>
    CSVlesen("c:\Downloads\AutoIt-Skripte\Entwicklung\ForumTests\20070720 Planung SONAR 2007.csv")

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

    Func CSVlesen($file) ;Liest den Inhalt der übegebebenen CSV-Datei in ein zweidimensionales Array und gibt dieses zurück (erstes Element enthält Anzahl Zeilen)
    Local $CountLines = _FileCountLines($file)
    Local $zeilen[$CountLines+1]
    Local $zeile
    $zeilen[0] = $CountLines
    $csv = FileOpen($file, 0)
    For $i = 1 To $CountLines
    $zeile = FileReadLine($csv, $i)
    If @error = -1 Then
    ExitLoop
    EndIf
    MsgBox(64, "Test", "Inhalt: " & $zeile) ;hier wird die ganze Zeile korrekt ausgegeben.
    $zeilen[$i] = StringSplit($zeile, ";")
    MsgBox(64, "Test", "Inhalt: " & $zeilen[$i]) ;ist scheinbar leer
    ;MsgBox(64, "Test", "Inhalt: " & $zeilen[$i][0]) ;erzeugt Fehlermeldung!
    Next
    FileClose($csv)
    Return $zeilen
    EndFunc

    [/autoit]

    So long,

    Mega

  • teh_hahn: Habe mal deine Funktion komplett übernommen aber beim Testen kommt wieder in Zeile 28 deines Codes der Fehler:
    ==> Array variable has incorrect number of subscripts or subscript dimension range exceeded.:
    MsgBox(64, "Test", "Inhalt: " & $a_rows[$i][0])
    MsgBox(64, "Test", "Inhalt: " & ^ ERROR

    Xenobiologist : Wie bereits geschrieben funktioniert es ja auch ohne Fehlermeldung wenn ich nicht Versuche, wie in Zeile 18 deines Codes auskommentiert, auf das Ergebnis von StringSplit() zuzugreifen. Spätestens wenn du versucht dir den Inhalt mit _ArrayDisplay(CSVlesen("test.csv")) anzuzeigen siehst du dass lediglich die erste "Zeile" des Arrays die Anzahl der Spalten enthält und die anderen "Zeilen" des Arrays leer sind.

    Meine CSV-Datei (test.csv) sieht - wie jede andere ;) - z. B. so aus:

    Code
    1. Spalte;2. Spalte;3. Spalte;4. Spalte;5. Spalte
    2. Zeile;1. Inhalt;2. Inhalt;3. Inhalt;4. Inhalt
    3. Zeile;5. Inhalt;6. Inhalt;7. Inhalt;8. Inhalt
    4. Zeile;9. Inhalt;10. Inhalt;11. Inhalt;12. Inhalt

    3 Mal editiert, zuletzt von jans16 (20. Juli 2007 um 13:49)

  • Könnte es vielleicht sein, dass hier ein Bug in AutoIt vorliegt.
    Wenn ich

    [autoit]

    $zeilen[$i]=StringSplit($zeile, ";")
    _ArrayDisplay($zeilen[$i])

    [/autoit]


    verwende, wird das Array, welches von StringSplit() erzeugt wird und als Element eines anderen Array (zeilen[$i]) abgelegt wird korrekt angezeigt.

  • Habe eine Lösung gefunden. Scheint zwar recht umständlich, aber Funktioniert!

    [autoit]

    Func CSVlesen($file) ;Liest den Inhalt der übegebebenen CSV-Datei in ein zweidimensionales Array und gibt dieses zurück (erstes Element enthält Anzahl Zeilen)
    Local $CountLines = _FileCountLines($file)
    StringReplace(FileReadLine($file, 1), ";", "") ;Nur um die Anzahl der Semikolons in einer Zeile herauszufinden (bessere Idee?)
    Local $CountCols = @extended + 1
    Local $zeilen[$CountLines+1][$CountCols]
    Local $zeile
    $zeilen[0][0] = $CountLines
    $csv = FileOpen($file, 0)
    For $i = 1 To $CountLines
    $zeile = FileReadLine($csv)
    If @error = -1 Then
    ExitLoop
    EndIf
    ;MsgBox(64, "Test", "Inhalt: " & $zeile) ;hier wird die ganze Zeile korrekt ausgegeben.
    $zeile = StringSplit($zeile, ";")
    For $j = 0 To $CountCols-1
    $zeilen[$i][$j] = $zeile[$j+1]
    Next
    ;MsgBox(64, "Test", "Inhalt: " & $zeilen[$i][0]) ;erzeugt keine Fehlermeldung mehr.
    Next
    FileClose($csv)
    Return $zeilen
    EndFunc

    [/autoit]

    @(VX-)Rexx: Ich weiß, ich tippe auch mal auf einen Bug... Aber wer sonst mal eine CSV-Datei einlesen möchte kann gerne meine Funktion ^^ verwenden. Die funktioniert jetzt wie gesagt wunderbar...

    • Offizieller Beitrag

    Hi,

    das ist alles so in Ordnung. Siehe hier:

    Spoiler anzeigen
    [autoit]

    #include<File.au3>
    #include<array.au3>
    CSVlesen("c:\Downloads\AutoIt-Skripte\Entwicklung\ForumTests\20070720 Planung SONAR 2007.csv")

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

    Func CSVlesen($file) ;Liest den Inhalt der übegebebenen CSV-Datei in ein zweidimensionales Array und gibt dieses zurück (erstes Element enthält Anzahl Zeilen)
    Local $CountLines = _FileCountLines($file)
    Local $zeilen[$CountLines + 1][2]
    Local $zeile
    $zeilen[0][0] = $CountLines
    $csv = FileOpen($file, 0)
    For $i = 1 To $CountLines
    $zeile = FileReadLine($csv, $i)
    If @error = -1 Then ExitLoop
    $zeilen[$i][0] = $i
    $zeilen[$i][1] = StringSplit($zeile, ";")
    MsgBox(64, "Test", "Nr(Zeile): " & $zeilen[$i][0])
    _ArrayDisplay( $zeilen[$i][1])
    Next
    FileClose($csv)
    Return $zeilen
    EndFunc ;==>CSVlesen

    [/autoit]

    So long,

    Mega

  • Zitat

    Original von Xenobiologist
    Hi,

    das ist alles so in Ordnung. Siehe hier:

    Einspruch!
    Ja, es geht so. Aber du hast auch explizit ein 2-dimensionales Array deklariert.
    Laut Hilfe von AutoIt (3.2.4.9):

    Zitat


    Data types in Arrays

    It was said that an Array contains only one datatype of the same type. But technically speaking, a Variant in AutoIt can contain anything from a number to a boolean value. So an AutoIt-Array could also contain different types, even other Arrays:

    $Array[0]=1
    $Array[1]=true
    $Array[2]="Text"
    $Array[3]=$AnotherArray


    Und genau der letzte Fall trifft in der ursprünglichen Version zu.
    Ist jetzt die Hilfe falsch?

    Einmal editiert, zuletzt von (VX-)Rexx (20. Juli 2007 um 16:38)

  • Zitat

    Original von BugFix
    Nein, es ist kein Bug. Du kannst nur nicht direkt auf ein Array innerhalb eines Array-Elements zugreifen. Du mußt es erst separieren:
    ...

    Und warum finde ich solch wesentliche Informationen nicht in der Hilfe/Doku (da wo die Grundlagen des Array abgehandelt werden) - oder bin ich einfach nur zu blöd zum lesen? ?(

    Mir scheint es fast so, als ob AutoIt an der gleichen Krankheit wie viele Linux-Projekte/-Programme leidet: funktional absolute Spitze, Doku mehr als nur mäßig. X( Hier vor allem bei tiefer gehender Dokumentation! Bei einer Script-Sprache (aber nicht nur bei dieser Art Sprachen) ist so etwas wesentlich!
    Wieviel Zeit könnte gespart werden, wenn nicht fast jede Kleinigkeit irgendwo im I-Net gesucht werden müßte! ... Okay, ich schweife langsam vom Thema ab... also Schluß mit dem Beitrag.

    • Offizieller Beitrag

    Ich habe noch keine Hilfe in der Qualität gesehen, die AutoIt bietet...
    Es gibt zu jedem Befehl (an der Vollständigkeit scheitern schon die meisten anderen [MS-]Dokus) vollständige Syntax, Erklärung, Hinweise und ein komplettes Beispiel (!).
    Du hast zwar scheinbar Recht, dass dein Problem nicht abgehandelt ist, aber man kann nunmal nicht alles darstellen - ansonsten bräuchte man wohl einige MB mehr und man bräuchte auch keine Foren wie dieses hier.
    Also auf die Doku lasse ich bei AutoIt nichts kommen =).

    peethebee

    • Offizieller Beitrag

    @(VX-)Rexx 
    Ich stimme dir insofern zu, dass dieser Punkt in der bisherigen Doku keinen Eingang gefunden hat und dies wünschenswert wäre.
    Andererseits kann ich mir nicht verkneifen zu sagen, dass jemand der Arrays in einem Array ablegt schon tiefergehende Programmierkenntnisse besitzen sollte (nicht zwingend in AutoIt, nur fürs Verständnis) und somit durch try & error nach spätestens 5 Minuten zu diesem Ergebnis kommt. ;)


    EDIT:
    Ich habe anhand deines Beispiels mal einen Beitrag für unser Wiki geschrieben.
    Arrays als Elemente eines Arrays

  • Zitat

    Original von BugFix
    Ich habe anhand deines Beispiels mal einen Beitrag für unser Wiki geschrieben.


    Danke für die Blumen ... nur mir gehören sie nicht. Ich hab den Thread nicht begonnen und auch keine Lösungen gegeben. Eben nur auf die nicht vollständige Doku verwiesen.

    Zitat

    Original von peethebee
    Ich habe noch keine Hilfe in der Qualität gesehen, die AutoIt bietet...


    Ich schon. Von IBM für Rexx. :D Und diese war deutlich besser. Ach ja, und Rexx gehörte - im Gegensatz zu AutoIt für Windows - zum Standardumfang von OS/2. Nur leider gibt es letzteres nicht mehr (von IBM). :weinen:

    Zitat

    Original von peethebee
    Es gibt zu jedem Befehl (an der Vollständigkeit scheitern schon die meisten anderen [MS-]Dokus) vollständige Syntax, Erklärung, Hinweise und ein komplettes Beispiel (!).
    Du hast zwar scheinbar Recht, dass dein Problem nicht abgehandelt ist, aber man kann nunmal nicht alles darstellen - ansonsten bräuchte man wohl einige MB mehr und man bräuchte auch keine Foren wie dieses hier.

    Das es zu jedem Befehl von AutoIt einen entsprechenden Eintrag in der Hilfe gibt - ebenso ja auch für die beiliegenden UDF's - habe ich ja auch nicht in Abrede gestellt. Über die Tiefe der jeweiligen Info läßt sich wahrscheinlich trefflich streiten; auch hätte ich nicht die Zeit, selber die Doku zu ergänzen.
    Informationen zu Array's sind für mich aber von wesentlicher Natur, so dass sie auch vollständig angegeben werden müßten. Und wenn in den Beispielen explizit darauf hingewiesen wird, das ein Array ein Element eines anderen Array sein kann (auch wenn nicht empfohlen), dann sollte auch vermerkt werden, wie auf die Elemente des eingebundenen Array zugegriffen werden kann!

    Zur Notwendigkeit des Forums:
    Viele der hier im Forum aufgeworfenen Fragen kann eine Doku gar nicht beantworten. Daher ist die Aussage mit dem "nicht Brauchen" des Forums wohl eher rhetorischer Natur.

    (Bitte jetzt keine Hinweise/Verweise, dass AutoIt Freeware ist und somit in Bezug auf Doku ausserhalb jeder Kritik steht!)

  • Wie schön, dass nun meine Bespiel-CSV-Datei im Wiki verewigt wurde... ;)8)

    Aber wenn mein ein echtes 2D-Array haben möchte spricht doch auch nichts gegen meine Funktion vom vorheriger Beitrag...

    Da wäre dann nur noch meine Frage, ob es eine elegantere Lösung gibt, die Anzahl der Semikolons herauszufinden? Ich habe keine Funktion gefunden, die direkt die Anzahl der Vorkommnisse eines Zeichens innerhalb eines Strings zurückgibt.