Probleme beim Einlesen von Strings



  • Hallo Leute,
    ich habe eine Datei mit folgendem Inhalt: (gleiche Formatierung)

    Vorname,Nachname,Straße,9,48273,Ort

    Diese versuche ich mit folgendem C-Code einzulesen:

    while(fscanf(dateizeiger,"%s,%s,%s,%hu,%i,%s\n",tmp_vorname,tmp_nachname,tmp_strasse,&tmp_hausnummer,&tmp_plz,tmp_ort) != EOF )
    

    Allerdings wird nun in die Variable tmp_vorname der komplette String gespeichert, d.h. die Kommas werden ignoriert. Leider weiß ich aber nicht warum. Kann mir evtl. jemand helfen?

    Gruß Torsten


  • Mod

    http://www.cplusplus.com/reference/cstdio/fscanf/

    Du suchst den Formatspezifizierer %[^,] . Dieser hat auch den Vorteil, dass man Leerzeichen im Namen haben darf.

    Weitere Schwächen im Programm:
    - Da gehört noch unbedingt eine Angabe der maximalen Länge dran! Also zum Beispiel %123s bzw. %123[^,] .
    - Was macht der arme Herr Mustermann, der in der Musterstraße 2a in 01067 Dresden wohnt? Ganzzahlen sind die falschen Datentypen für Postleitzahl und Hausnummer. Lass dich nicht in die Falle locken! Bloß weil "Nummer" oder "Zahl" im Namen ist, ist es noch lange keine Zahl. Weitere Beispiele: Telefonnummer, Kontonummer. Leitfaden: Ergibt die Differenz zweier Werte eine sinnvolle Größe? Wenn nein, dann ist es keine Zahl, selbst wenn es aus Ziffern besteht.*
    - Warum prüfst du nur auf EOF? Was, wenn etwas anderes beim Lesen schief geht? Prüf doch besser, ob die Anzahl der erfolgreichen Leseoperationen der Anzahl der geforderten Leseopterationen entspricht. Der Code bleibt bis auf das EOF der gleiche, kommt aber auf einmal mit allen möglichen Fehlern klar.

    *: Offtopic, aber für dich bestimmt auch relevant: Geld != Fließkomma (float, double, …)



  • Vielen Dank für deine schnelle Antwort!

    Also habe ich den Code mal folgendermaßen angepasst:

    while(fscanf(dateizeiger,"%2056s[^,]%2056s[^,]%2056s[^,]%hu[^,]%i[^,]%2056s\n",tmp_vorname,tmp_nachname,tmp_strasse,&tmp_hausnummer,&tmp_plz,tmp_ort) != EOF )
    

    Funktioniert aber leider trotzdem nicht, oder habe ich da etwas falsch gemacht? Die tmp_ Variablen sind mit 2056 Zeichen allokiert, da ich diese anschließend mit strlen auf die größe Überprüfe und dann dynamisch allokiere. Für einen Zusatzbuchstaben an der Hausnummer habe ich mir auch schon etwas ausgedacht, das habe ich allerdings noch etwas hinterher hängen lassen 😃

    Wie genau du das mit der Überprüfung auf EOF meinst, habe ich nicht verstanden. EOF nehme ich ja nur, da ich ja nicht weiß, wie viele Zeilen die Datei hat.

    Gruß



  • Dein Compiler kann C99 oder aktueller? Und du hast das auch aktiviert?

    Der Vorname sollte selten 2000 Zeichen lang sein. Selbst an 100 Zeichen wird man nur selten scheitern. Also sollten 100 Zeichen da fast immer mehr als ausreichend sein.


  • Mod

    while(fscanf(dateizeiger,"%2056[^,],%2056[^,],%2056[^,],%hu,%i,%2056s\n",tmp_vorname,tmp_nachname,tmp_strasse,&tmp_hausnummer,&tmp_plz,tmp_ort) == 6 )
    

    Guck dir unbedingt nochmal genau an, wie scanf funktioniert. Das was du da probiert hast lässt darauf schließen, dass du den Formatstring überhaupt gar nicht verstanden hast.



  • Der letzte Formatspecifier sollte auch nicht s sein.
    Es gibt auch Orten mit Leerzeichen. Da du da aber kein Komma mehr hast, solltest du auf Newline prüfen.
    [^\n] sollte gehen.


  • Mod

    Wo wir schon dabei sind:
    http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/

    Aber man braucht es ja für so ein Übungsprogramm (es ist doch zur Übung, oder?) nicht zu übertreiben. Aber hiesige Konventionen sollten schon funktionieren. Herr Mustermann aus der Musterstraße 2a in 01067 Dresden würde gerne immer noch in deine Datenbank.



  • SeppJ schrieb:

    Wo wir schon dabei sind:
    http://www.kalzumeus.com/2010/06/17/falsehoods-programmers-believe-about-names/

    Aber man braucht es ja für so ein Übungsprogramm (es ist doch zur Übung, oder?) nicht zu übertreiben. Aber hiesige Konventionen sollten schon funktionieren. Herr Mustermann aus der Musterstraße 2a in 01067 Dresden würde gerne immer noch in deine Datenbank.

    Hey,

    ja ist nur zur Übung, ich versuche zurzeit C zu lernen, deshalb auch die Typischen Anfängerfehler ..

    Andere Frage: Wie würde ich dann eine Datei einlesen, die folgendermaßen aufgebaut ist:?

    03.07.2013 13:36:31	http://google.de/	http://google.de/
    

    Zur Erklärung, das Format ist folgendermaßen:

    dd.mm.yyyy hh:mm:ss [html: title] [url]
    

  • Mod

    Wie würdest du es denn machen? Schließlich lernst du nichts, wenn ich dir einfach eine Lösung hin klatsche. Versuch es so gut wie möglich, selber zu machen. Keine 2 Minuten Wischiwaschilösung, sondern wirklich mal die scanf-Referenzen studieren, Beispiele angucken, eigenständige Internetrecherche zum Einlesen von Datum, Uhrzeit und URLs in C. Diese Tätigkeiten sind ungeheuer wichtig beim Programmieren. Die lernst du nicht durch Anschauen einer Komplettlösung.

    Was ist der Unterschied zwischen den beiden URLs?



  • SeppJ schrieb:

    Wie würdest du es denn machen? Schließlich lernst du nichts, wenn ich dir einfach eine Lösung hin klatsche. Versuch es so gut wie möglich, selber zu machen. Keine 2 Minuten Wischiwaschilösung, sondern wirklich mal die scanf-Referenzen studieren, Beispiele angucken, eigenständige Internetrecherche zum Einlesen von Datum, Uhrzeit und URLs in C. Diese Tätigkeiten sind ungeheuer wichtig beim Programmieren. Die lernst du nicht durch Anschauen einer Komplettlösung.

    Was ist der Unterschied zwischen den beiden URLs?

    Also ich habe mir überlegt, jedes Zeichen einzeln einzulesen. Die Trennung von Uhrzeit und Datum ist dabei nicht das Problem. Es geht darum eher dass nach der Uhrzeit dann der Inhalt aus dem html-title-tag abgespeichert ist. Dieser Inhalt kann jedoch aber auch Leerzeichen enthalten. D.H. ich kann schonmal das Leerzeichen nicht als Trennzeichen überprüfen, da es ja auch innerhalb des Titels vorkommen kann. Deshalb meine Idee, irgendwie nach dem Leerzeichen die darauffolgenden Zeichen auf "http://", "https://", "ftp://" und "file:///" zu überprüfen, damit ich dann weiß, dass es sich jetzt um die URL handelt. Allerdings weiß ich nicht, wie ich dies umsetzen soll.



  • Sorry wegen dem Doppelpost aber mir ist eine andere Idee gekommen:

    while(fscanf(dateizeiger,"%hu.,%hu.,%hu,%hu:,%hu:,%hu,%9000s\n", &day, &month, &year, &hour, &minute, &second, gesstring) == 7) {
    				printf("Zeit: %hu:%hu:%hu\n", hour, minute, second);
    				printf("Tag: %hu %hu %hu\n", day, month, year);
    				printf("Zeichenkette: %s\n", gesstring);
    			}
    

    Den am Schluss eingelesenen String überprüfe ich dann von Hinten nach Vorne nach Leerzeichen. Da eine URL ja kein Leerzeichen enthalten darf, ist das erste Leerzeichen vor dem Anfang vom Pfad. Allerdings funktioniert mein Code nicht.



  • Scromop schrieb:

    while(fscanf(dateizeiger,"%hu.,%hu.,%hu,%hu:,%hu:,%hu,%9000s\n", &day, &month, &year, &hour, &minute, &second, gesstring) == 7)
    

    Hast du wirklich Punkte und Kommas im Datum?
    Hast du wirklich Doppelpunkte und Kommas im Datum?



  • DirkB schrieb:

    Scromop schrieb:

    while(fscanf(dateizeiger,"%hu.,%hu.,%hu,%hu:,%hu:,%hu,%9000s\n", &day, &month, &year, &hour, &minute, &second, gesstring) == 7)
    

    Hast du wirklich Punkte und Kommas im Datum?
    Hast du wirklich Doppelpunkte und Kommas im Datum?

    Stimmt, die Kommas brauche ich ja gar nicht 🙄

    Aber wenn ich das ganze hier so einlesen lasse, werden Leerzeichen im String nicht mit eingelesen. Wie sorge ich dafür, dass der String komplett bis zum Ende eingelesen wird?



  • Indem du den richtigen Formatspecifier nimmst: %[

    fscanf(dateizeiger,"%hu.%hu.%hu %hu:%hu:%hu %9000[^\n]", ....
    

    Wie groß ist denn dein gesstring? 9000 oder 9001?
    Bei scanf werden die Anzahl der maximal lesbaren Zeichen angegeben. Da muss immer noch Platz für die '\0' bleiben.
    Bei 9000 ist der Formatstring falsch.


Anmelden zum Antworten