Seite 1 von 1

CSV Reader

Verfasst: 30.03.2013 15:06
von KeyKon
Hat zufällig einer eine Prozedur die eine CSV in eine Strukturierte Liste/Array einließt und will sie hier veröffentlichen, war mal wieder nicht in der Lage mit der SuFu was zu finden.
Dachte eigentlich das ist ja schnell gemacht nur muss sie auch mit Feldern in denen Zeilenumbrüche oder Kommas vorkommen (Die sind dann durch Anführungszeichen eingeschlossen) zurechtkommen, da ist mir spontan keine performante Möglichkeit eingefallen...

Achja bitte steinigt mich nicht wenn sowas in 10 Zeilen zu lösen ist, weiht mich in dem Fall einfach ein :mrgreen:

LG KeyKon

Re: CSV Reader

Verfasst: 30.03.2013 19:21
von #Ton

Code: Alles auswählen

EnableExplicit

Structure struc_INPUT
  val1.l
  val2.l
  val3.l
EndStructure


Procedure ReadCSVFile(Array a.struc_INPUT(1), CSV_Path.s)
  
  Protected.l z            = #Null
  Protected.s SepChar      = ";"
  Protected.s String       = ""
  Protected.s StringNeeded = ""
  
  
  
  ;> (CSV-)Datei einlesen
  If ReadFile(0, CSV_Path) = #Null
    MessageRequester("Error", "Couldn't read file:" + Chr(13) + CSV_Path)
    End
  EndIf
  
  
  
  ;> Array-Feldgröße anpassen
  While Eof(0) = #Null
    ReadString(0)
    z+1
  Wend
  
  ReDim a(z-1)
  
  z = 0
  
  FileSeek(0,0)
  
  
  
  ;> Array füllen
  While Eof(0) = #Null
    
    String       = ReadString(0, ReadStringFormat(0))
    
    StringNeeded = Left ( String, FindString(String, SepChar,0)-1 )
    String       = Right( String, Len(String)-FindString(String, SepChar, 0) )
    a(z)\val1    = Val  ( StringNeeded )
    
    StringNeeded = Left ( String, FindString(String, SepChar,0)-1 )
    String       = Right( String, Len(String)-FindString(String, SepChar, 0) )
    a(z)\val2    = Val ( StringNeeded )
    
    a(z)\val3    = Val(String)
    
    z+1
    
  Wend
  
  
  
  CloseFile(0)
  
EndProcedure


Global Dim csv.struc_INPUT(#Null)


ReadCSVFile(csv(), GetHomeDirectory()+"Desktop\test.csv")

Zugehöriger CSV-Dateiinhalt zum testen:
648;98;138
3186;3971;398
18638;34834;34384

Re: CSV Reader

Verfasst: 30.03.2013 20:30
von NicTheQuick
Damit kann man aber keine Strings einlesen und schon gar nicht Strings, die in Anführungszeichen stehen und sich über mehrere Zeilen erstrecken, z.B. das hier:
Vorname,Nachname,PLZ,Adresse, Telefon
Max,Mustermann,53118,"Musterweg 18
Musterhause", "01234/56789"

Re: CSV Reader

Verfasst: 30.03.2013 21:53
von KeyKon
Genau, für einfache Zahlenwerte/Strings hatte ich es auch schon und war ganz Happy, bis ich gemerkt hab das da unter Umständen auch Kommas und Zeilenumbrüche dabei sind (Nur bei diesen ist dann auch ein Anführungszeichen)

Trotzdem danke für die Mühe! Da sich auf die schnelle keiner gemeldet hat werd ich mich selbst an die Umsetzung machen.
Wollte ja nur mal abchecken ob das vll schon jemand in der Schublade hat, man muss sich ja keine unnötige Arbeit machen^^

LG KeyKon

Re: CSV Reader

Verfasst: 31.03.2013 08:17
von Danilo
Hier ein Character-Scanner dafür:

Code: Alles auswählen

EnableExplicit

Structure CSVEntry
    List Item.s()
EndStructure

#CSV_WithDoubleQuotes    = 0 ; add double quotes to the output string (default)
#CSV_WithoutDoubleQuotes = 1 ; remove double quotes from the output string

Procedure ReadCSV(*p.Character, separator.c, List lst.CSVEntry(), flags = #CSV_WithDoubleQuotes)
    Protected item.s
    
    ClearList( lst() )
    
    If *p = 0 Or *p\c = 0
        ProcedureReturn ; empty string
    EndIf
    
    AddElement(lst())
    
    While *p\c <> 0
        While *p\c <> 0
            If *p\c = 34                           ; DoubleQuote start
                If flags = #CSV_WithDoubleQuotes
                    item + Chr(*p\c)               ; add starting DoubleQuote
                EndIf
                *p + SizeOf(Character)
                While *p\c <> 0 And *p\c <> 34     ; scan for DoubleQuote end
                    If *p\c <> 10 And *p\c <> 13   ; do not add cariage return and line feed while in string
                        item + Chr(*p\c)
                    EndIf
                    *p + SizeOf(Character)
                Wend
                If *p\c = 34
                    If flags = #CSV_WithDoubleQuotes
                        item + Chr(*p\c)           ; add ending DoubleQuote
                    EndIf
                    *p + SizeOf(Character)
                EndIf
                Continue                           ; continue scanning
            ElseIf *p\c = separator                ; separator found. exit inner loop
                *p + SizeOf(Character)
                Break
            ElseIf *p\c = 10 Or *p\c = 13          ; cariage return or line feed found outside string: Break
                Break
            Else                                   ; other character found, so add it to current item
                item + Chr(*p\c)
                *p + SizeOf(Character)
            EndIf
        Wend
        
        AddElement(lst()\Item())                   ; add current item to the list items
        lst()\Item() = item
        item=""
        
        If *p\c = 13                               ; for #CR$, #LF$, #CRLF$, #LFCR$:
            AddElement(lst())                      ; end of line found, so add a new list entry
            *p + SizeOf(Character)
            If *p\c = 10
                *p + SizeOf(Character)
            EndIf
        ElseIf *p\c = 10
            AddElement(lst())
            *p + SizeOf(Character)
            If *p\c = 13
                *p + SizeOf(Character)
            EndIf
        EndIf
    Wend
    
    FirstElement(lst())
    If ListSize(lst())=1 And ListSize(lst()\Item())=0
        ClearList(lst())
    EndIf
EndProcedure

Procedure.i ReadCSVFile(filename.s, separator.c, List lst.CSVEntry(), flags = #CSV_WithDoubleQuotes)
    Protected file, *mem, format, line.s, stringpointer.i, result.i
    ClearList( lst() )
    file = ReadFile(#PB_Any,filename)
    If file
        format = ReadStringFormat(file)
        *mem = AllocateMemory((Lof(file)+10)*SizeOf(Character)) ; read file into memory, line by line
        If *mem
            stringpointer = *mem
            While Not Eof(file)
                line = ReadString(file,format)
                If Eof(file) = 0
                    line + #LF$
                EndIf
                CopyMemoryString(@line,@stringpointer)
            Wend
            ReadCSV(*mem,separator,lst(),flags)                       ; call ReadCSV() on the memory
            result = #True
            FreeMemory(*mem)
        EndIf
        CloseFile(file)
    EndIf
    ProcedureReturn result
EndProcedure




NewList entries.CSVEntry()

Define csv.s

csv = "Vorname,Nachname,PLZ,Adresse, Telefon"+#LF$
csv + "Max,Mustermann,53118,"+#DQUOTE$+"Musterweg 18, "+#LF$
csv + "Musterhausen"+#DQUOTE$+", "+#DQUOTE$+"01234/56789"+#DQUOTE$

ReadCSV(@csv,',',entries())

ForEach entries()
    ForEach entries()\Item()
        Debug Trim(entries()\Item())
    Next
    Debug "-----"
Next

Debug "-----------------------------------"

csv = "648;98;138"+#CRLF$
csv + "3186;3971;398"+#LFCR$
csv + "18638;34834;34384"+#LF$
csv + "1920;8;1977"+#CR$
csv + "1;2;3"

ReadCSV(@csv,';',entries())

ForEach entries()
    ForEach entries()\Item()
        Debug Trim(entries()\Item())
    Next
    Debug "-----"
Next

Define url.s = "http://download.finance.yahoo.com/d/quotes.csv?s=C+GLAD+HIMX+INSP+INTU+HRB+JTX+PODD+SILU+WFC&f=snoghl1b2b3p2"
Define filename.s = GetTemporaryDirectory()+"quotes.csv"

If InitNetwork()
    ReceiveHTTPFile(url,filename)
EndIf

Debug "- File ----------------------------"

If ReadCSVFile(filename,',',entries(),#CSV_WithoutDoubleQuotes)

    ForEach entries()
        ForEach entries()\Item()
            Debug Trim(entries()\Item())
        Next
        Debug "-----"
    Next
Else
    Debug "unable to read file"
EndIf

DeleteFile(filename)

Re: CSV Reader

Verfasst: 31.03.2013 18:00
von Danilo
Habe mal noch 2 Flags hinzugefügt:

Code: Alles auswählen

#CSV_WithDoubleQuotes    = 0 ; add double quotes to the output string (default)
#CSV_WithoutDoubleQuotes = 1 ; remove double quotes from the output string
So kannst Du auswählen ob die Anführungszeichen Teil des Ausgabestrings sind, oder nicht.

Re: CSV Reader

Verfasst: 01.04.2013 11:31
von Kiffi
@Danilo: Danke! :allright:

Grüße ... Kiffi