CSV Reader

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
KeyKon
Beiträge: 1412
Registriert: 10.09.2004 20:51
Computerausstattung: Laptop: i5 2,8 Ghz, 16GB DDR3 RAM, GeForce 555GT 2GB VRAM
PC: i7 4,3 Ghz, 32GB DDR3 RAM, GeForce 680 GTX 4GB VRAM
Win10 x64 Home/Prof
PB 5.30 (64bit)
Wohnort: Ansbach
Kontaktdaten:

CSV Reader

Beitrag 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
(\/) (°,,,°) (\/)
#Ton
Beiträge: 11
Registriert: 30.03.2013 11:57

Re: CSV Reader

Beitrag 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
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: CSV Reader

Beitrag 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"
Benutzeravatar
KeyKon
Beiträge: 1412
Registriert: 10.09.2004 20:51
Computerausstattung: Laptop: i5 2,8 Ghz, 16GB DDR3 RAM, GeForce 555GT 2GB VRAM
PC: i7 4,3 Ghz, 32GB DDR3 RAM, GeForce 680 GTX 4GB VRAM
Win10 x64 Home/Prof
PB 5.30 (64bit)
Wohnort: Ansbach
Kontaktdaten:

Re: CSV Reader

Beitrag 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
(\/) (°,,,°) (\/)
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: CSV Reader

Beitrag 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)
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: CSV Reader

Beitrag 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.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Benutzeravatar
Kiffi
Beiträge: 10714
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Re: CSV Reader

Beitrag von Kiffi »

@Danilo: Danke! :allright:

Grüße ... Kiffi
a²+b²=mc²
Antworten