2016-04-11 7 views
0

Sagen dies die Datei, die ich lesen will:Wie fscanf() verwendet wird, um Strings mit mehreren Formaten zu erhalten?

07983988 REMOVE String1 
13333337 ADD String4 100 
34398111 TRANSFER String5 String6 100 

Diejenigen, die nur drei gültige Formattypen sind.

ich den folgenden Code-Block bin mit zu überprüfen, was das Format der Zeile analysiert:

// Read from file. 
    while (!feof(fd)) { 

     // Check for format. 
     if (fscanf(fd, "%d %s %s %s %lf", &timestamp, transaction_type_str, company1, company2, &value)) { 
      node_t *transaction = create_node((long int)timestamp, 1, company1, company2, value); 
      add_node(transactions, transaction); 
     } else if (fscanf(fd, "%d %s %s", &timestamp, transaction_type_str, company1)) { 
      node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, 0); 
      add_node(transactions, transaction); 
     } else if (fscanf(fd, "%d %s %s %lf", &timestamp, transaction_type_str, company1, &value)) { 
      node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, value); 
      add_node(transactions, transaction); 
     } 

Dies jedoch ist mir eine Endlosschleife zu geben. Ich bin neu in der Datei I/O in C, und ich frage mich, ob es besser ist, eine tokenisierte Ansatz oder Linie basierte Format Suche Ansatz zu verwenden.

+1

Das Problem mit 'fscanf()' ist es ist destruktiv. Sie müssen fast sicher 'fgets()' oder 'getline()' verwenden, um eine Zeile zu lesen, und dann eine Analyse mit 'sscanf()' durchführen. Dadurch können Sie es erneut versuchen, wenn die erste Analyse fehlschlägt. –

+0

Ich benutze ANSI C, also nehme ich an, dass 'fgets()' meine einzige Option ist? –

+1

Es hängt davon ab, was Sie mit "ANSI C" meinen. Wenn Sie bei C89/C90 stecken bleiben, tut es mir leid - Sie sollten C11 oder C99 verwenden können. Es hängt auch davon ab, ob das bedeutet "nur Funktionen definiert durch (die relevante Version von) der Norm" oder etwas anderes. Als Ausgangspunkt ist 'fgets()' jedoch das am zuverlässigsten verfügbare Werkzeug. Benutze es, um eine Zeile zu lesen: 'char puffer [4096]; while (fgets (buffer, sizeof (buffer), fd)! = 0) {... analysiere den Puffer mit sscanf() etc ...} '(nicht die Nichtbenutzung von' feof() '). –

Antwort

1

Kurz umrissen:

char buffer[4096]; 

while (fgets(buffer, sizeof(buffer), fd) != 0) 
{ 
    int offset; 
    if (sscanf(buffer, "%d %s %n", &timestamp, transaction_type_str, &offset) == 2) 
    { 
     char *residue = buffer + offset; 
     if (strcmp(transaction_type_str, "REMOVE") == 0) 
     { 
       if (sscanf(residue, "%s", company1) == 1) 
        …process remove… 
       else 
        …report error, etc… 
     } 
     else if (strcmp(transaction_type_str, "ADD") == 0) 
     { 
      if (sscanf(residue, "%s %lf", company1, &value) == 2) 
       …process add… 
      else 
       …report error, etc… 
     } 
     else if (strcmp(transaction_type_str, "TRANSFER") == 0) 
     { 
      if (sscanf(residue, "%s %s %lf", company1, company2, &value) == 3) 
       …process transfer… 
      else 
       …report error, etc… 
     } 
     else 
     { 
      …report error and continue or break… 
     } 
    } 
} 

Sie können die Analyse strenger, zum Beispiel machen und bestand darauf, dass es keine nicht verwendeten Daten nach dem sekundären sscanf() Anruf beendet ist, etc. Das ist knifflig ist, aber bei weitem nicht unmöglich .

Dies deckt den angeforderten Code ab - er identifiziert, welcher Transaktionstyp angefordert wird, bevor der Rest der Zeile analysiert wird.

+0

Yo, ich liebe dich, Mann. –

0

Das Problem besteht darin, dass Sie den Feof-Test als While-Steuerelement verwenden. Hier sind Gründe, warum es nicht funktioniert.

Why is “while (!feof (file))” always wrong?

FAQ > Why it's bad to use feof() to control a loop

Die Funktion prüft den Ende-der-Datei-Indikatoren, nicht in dem Strom selbst. Das bedeutet, dass eine andere Funktion tatsächlich für die Einstellung verantwortlich ist, dass der Indikator anzeigt, dass EOF erreicht wurde. Dies würde normalerweise von der Funktion durchgeführt werden, die das Lesen durchgeführt, das EOF getroffen hat. Wir können dann das Problem zu dieser Funktion folgen, und wir finden, dass die meisten gelesenen Funktionen EOF setzen, sobald sie alle Daten gelesen haben, und dann führte einen letzten Lesevorgang durch, der keine Daten, nur EOF ergab.

In diesem Sinne, wie zeigt es sich in einem Fehler in unserem Code-Schnipsel? Einfach ... wie das Programm die Schleife durchläuft, um die letzte Zeile der Daten zu erhalten, arbeitet fgets() normal, ohne EOF, zu setzen, und wir drucken die Daten aus. Die Schleife kehrt nach oben zurück und der Aufruf an feof() gibt FALSE zurück, und wir beginnen, die Schleife erneut zu durchlaufen. Diesmal sieht und setzt fgets() EOF, aber dank unserer armen Logik, fahren wir fort, den Puffer trotzdem zu verarbeiten, ohne zu merken, dass sein Inhalt jetzt undefiniert ist (höchstwahrscheinlich unberührt von der letzten Schleife).

0

Verwenden Sie fgets() und dann sscanf() mit dem Spezifizierer " %n", um den Scan-Abschluss zu erkennen.

Durch Erkennung, ob der Scan das Ende erreicht hat und kein zusätzlicher Text in der Zeile war, haben wir eine klare und symmetrische Parserkennung. Ähnlich wie der ursprüngliche Code von OP.

#define BUFSIZE 200 
char buf[BUFSIZE]; 

while (fgets(buf, sizeof buf, fd) != NULL) { 
    int n = 0; 
    if (sscanf(buf, "%d %s %s %s %lf %n", 
     &timestamp, transaction_type_str, company1, company2, &value, &n)); 
    if (n > 0 && buf[n] == '\0') { 
    node_t *transaction = create_node((long int)timestamp, 1, company1, company2, value); 
    add_node(transactions, transaction); 
    continue; 
    } 

    n = 0; 
    sscanf(buf, "%d %s %s %n", 
     &timestamp, transaction_type_str, company1, &n)); 
    if (n > 0 && buf[n] == '\0') { 
    node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, 0); 
    add_node(transactions, transaction); 
    continue; 
    } 

    n = 0; 
    sscanf(buf, "%d %s %s %lf %n", 
     &timestamp, transaction_type_str, company1, &value, &n); 
    if (n > 0 && buf[n] == '\0') { 
    node_t *transaction = create_node((long int)timestamp, 1, company1, NULL, value); 
    add_node(transactions, transaction); 
    continue; 
    } 

    Handle_BadLine(buf); // do not use transaction_type_str, company1, company2, value, n 
} 

Hinweis: Die Verwendung von "%s" ist gefährlich.Besser die Breite zu begrenzen

Verwandte Themen