2017-11-19 3 views
1

Lassen Sie uns sagen, dass ich eine Textdatei (hw.dat) haben, die Daten (Name, Höhe (cm), Gewicht (kg)) aufgeführt:Scannen separat einen Satz und Nummer (n) in C

Yuri   164  80 
Lai San Young 155  60 
John Wayne  180  93 

und die Liste wird fortgesetzt.

würde Ich mag alle Daten in diesem Format scannen und drucken:

name: Yuri, height: 164, weight: 80 
name: Lai San Young, height: 155, weight: 60 

und so weiter.

Hier ist mein fehlgeschlagener Versuch (Codesegmente). Ich wollte, Code schreiben, der die hw.dat Datei Zeile für Zeile liest, während die Daten Zeile für Zeile den Ausdruck:

double h, w; 
char name[100]; 

FILE *fr; 
fr = fopen ("hw.dat", "r"); 

while (fscanf(fr,"%[^\n]s %lf %lf", name, &h, &w)!=EOF) 
{ 
    printf ("name: %s, height: %lf, weight: %lf \n", name, h, w); 
} 

fclose (fr); 

Die% [^ \ n] s „frisst“ die ganze Linie. Ich kann auch% s nicht verwenden, da die Anzahl der Wörter der Namen unterschiedlich ist. Also, ich frage mich, ob es sowieso ist, um das Scannen zu trennen ... oder gibt es eine bessere Möglichkeit, dieses Problem zu nähern ...

Vielen Dank.

+0

Lesen Sie die ganze Zeile, dann finden Sie die letzten zwei Leerzeichen (diejenigen, die den Namen von den Zahlen trennen und die zwei Zahlen trennen). Extrahiere die zwei Zahlen und analysiere sie, und du erhältst den Namen (wahrscheinlich mit einigen nachgestellten Leerzeichen, die du trimmen kannst). –

+0

Verwenden Sie 'fgets' und analysieren Sie die Zeichenfolge selbst. –

+0

'% [^ \ n] * c% lf% lf'? –

Antwort

0

Versuchen

fscanf(fr,"%99[^0-9]%lf%lf ", name, &h, &w)!=EOF) 

den Namen am Anfang der Zeile Dies wird essen, dann sind die Zahlen und dann die neue Linie.

Sie müssen den Namen zuschneiden, um die Leerzeichen am Ende zu entfernen. How do I trim leading/trailing whitespace in a standard way? sollte Ihnen helfen

+0

Ich hätte '! = EOF' ->' == 3' setzen sollen –

0

Ein anderer Standard Weg, um das Problem zu nähern, ist einfach mit einem Zeiger am Ende der Zeile gesetzt, und dann Backup - Trimmen Leerzeichen (und Null-Terminierung), bis ein Buchstabe oder eine Ziffer gefunden wird - - Dann sichern Sie einfach, bis Sie das nächste Leerzeichen finden. Da der Zeiger nun zeigt auf die letzte whitepace vor weight, speichern nur einen Zeiger auf current + 1, die zu Beginn des weight (Wiederholung wieder für height)

Sie haben nun darauf gespeichert einen Zeiger auf height und der Zeiger zeigt nun bis zum letzten Leerzeichen vor height. Einfach weiter über Whitespace (nullendig, wie Sie gehen), bis Sie entweder den nächsten Buchstaben oder die nächste Ziffer erreichen (was das Ende des Namens sein wird) oder Sie den Anfang der Zeichenfolge (etwas schief gelaufen und Sie didn ' t finden `Name, Höhe, Gewicht).

Da Sie waren nul abbreche bis zu diesem Punkt, wissen Sie, der Puffer Sie jetzt lesen enthält nur die name, so können Sie einfach Ihre Ausgabe drucken können, und gehen Sie die nächste Zeile lesen. Es gibt absolut nichts, was man einfach nicht zu Fuß einen Zeiger (oder ein Paar von Zeigern) nach unten eine Zeichenfolge (oder bis eine Zeichenfolge in diesem Fall) analysieren kann

es insgesamt Einlochen, könnten Sie etwas Ähnliches wie die folgenden tun:

#include <stdio.h> 
#include <ctype.h> 

enum { MAXHW = 2, MAXC = 512 }; /* if you need constants, define them */ 

int main (int argc, char **argv) { 

    char buf[MAXC] = ""; /* line buffer */ 
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin; 

    if (!fp) { /* validate file open for reading */ 
     fprintf (stderr, "error: file open failed '%s'.\n", argv[1]); 
     return 1; 
    } 

    while (fgets (buf, MAXC, fp)) { /* read each line */ 
     char *p = buf,    /* pointer to buf */ 
      *hw[MAXHW] = {NULL}; /* array of MAXHW pointers */ 
     int ndx = 0;    /* array index */ 

     while (*p) p++;    /* find end of buf */ 
     p--;      /* backup to last char */ 

     while (p > buf) { /* while pointer within buf */ 
      /* loop checking if char is a trailing space, tab, newline, ... */ 
      while (p > buf && isspace (*p)) 
       *p-- = 0; /* overwrite with nul-terminating char */ 
      /* loop checking each char is a letter or digit */ 
      while (p > buf && isalnum (*p)) 
       p--;  /* just backup to previous char */ 
      hw[ndx++] = p + 1; /* space before word found, save ptr to word */ 
      if (p != buf) /* if not at beginning */ 
       *p = 0;  /* nul-terminate */ 
      else 
       break;   /* at beginning - bail */ 
      if (ndx == MAXHW) /* if both h & w filled */ 
       break;   /* bail */ 
      p--; /* backup to previous and keep going */ 
     } 
     if (p > buf && ndx == MAXHW) { /* not at beginning & H & W found */ 
      p--; /* backup to previous */ 
      /* trim trailing whitespace to end of name */ 
      while (p > buf && isspace (*p)) 
       *p-- = 0; 
     } 
     /* output results */ 
     printf ("name: %s, height: %s, weight: %s\n", buf, hw[1], hw[0]); 
    } 
    if (fp != stdin) fclose (fp); /* close file if not stdin */ 

    return 0; 
} 

Beispiel Verwendung/Output

$ ./bin/readhw <dat/hw.dat 
name: Yuri, height: 164, weight: 80 
name: Lai San Young, height: 155, weight: 60 
name: John Wayne, height: 180, weight: 93 

Es gibt viele, viele verschiedene Möglichkeiten, wie Sie dies tun können. Sie könnten ctype.h nicht verwendet und geprüft haben, z.B.if (p > buf && (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n') mit den expliziten Prüfungen für Leerzeichen anstelle von isspace(), etc .. Sie könnten strpbrk verwenden, um in der Zeichenfolge für Ihre erste Ziffer vorwärts zu scannen und arbeitete von dort vorwärts und rückwärts. Egal wie Sie es tun, der Schlüssel ist, einfach Ihre Schnur auf ein Blatt Papier zu schreiben und einen Stift zu verwenden, um Ihre Zeigerposition nach vorne und zurück zu bewegen, während Sie das Testen und Indizieren herausfinden, das Sie brauchen.

Schauen Sie sich die Dinge an und lassen Sie mich wissen, wenn Sie weitere Fragen haben.