2010-09-21 11 views
9

Problem: Ich muss identifizieren können, wenn zwei Leerzeichen hintereinander auftreten.Wie lese ich Leerraum mit scanf in c?

Ich habe folgende Fragen lauten:

how to read a string from a \n delimited file

how to read scanf with spaces

Und ich bin mir bewusst, scanf Probleme: http://c-faq.com/stdio/scanfprobs.html

Eingang in folgendem Format sein:

1 5 3 2 4 6 2 1 9 0 

Zwei weiße Leerzeichen zeigen an, dass die nächste Datenmenge behandelt und mit sich selbst verglichen werden muss. Die Länge der Linie ist unbekannt und die Anzahl oder ganzen Zahlen in jeder Gruppe ist unbekannt. Zwei Whitespaces sind die Trennzeichen für den nächsten Datensatz.

Während ich fgets und verschiedene eingebaute Funktionen verwenden kann, um dieses Problem zu lösen, bin ich an dem Punkt, wo die Lösung des Problems mit scanf zu diesem Zeitpunkt wahrscheinlich einfacher sein wird. Wenn dies nicht der Fall ist, wird die meiste Arbeit mit fgets, strtok und atoi erledigt, aber ich muss immer noch zwei Leerzeichen in einer Zeile identifizieren.

Im Folgenden werden Ganzzahlen verwendet, bis ein Nicht-Integer eingegeben wird.

 
while (scanf ("%d", &x) == 1) 

Was ich brauche es tun, ist auch zu lesen Whitespaces und wenn es zwei aufeinander folgende Leerzeichen Ich werde das Programm etwas anderes mit dem nächsten Satz von Daten zu tun.

Und wenn ich einen weißen Raum bekomme ich weiß nicht, wie zu sagen:

 
if ((input == "whitespace") && (previousInput == "whitespace")) 
    ya da ya da 
else (input == "whitespace") 
    ya da ya da 
else 
    ya da ya da 

ich Ihre Zeit zu schätzen und danken Ihnen für Ihre Hilfe.

Lektion gelernt: Während eine Lösung für scanf von Jonathan Leffler unten geschrieben wird, war die Lösung ein wenig einfacher mit getc (haft, die weniger intime Kenntnis der inneren scanf, reguläre Ausdrücke und Zeichen). Im Nachhinein würde eine bessere Kenntnis der regulären Ausdrücke, scanf und char das Problem leichter machen und natürlich wissen, welche Funktionen verfügbar sind und welche von Anfang an die beste wäre.

+2

Das ist ein ziemlich grässliches Eingabeformat. Wenn Sie dafür verantwortlich sind, gestalten Sie es neu. Wenn Sie, wie ich vermute, eine Hausaufgabe bekommen haben, Pech - sie sind ein sadistischer Haufen, Ihre Lehrer. –

+3

Beachten Sie, dass "weißer Raum" sich von "zwei Räumen" unterscheidet; "Leerraum" bedeutet üblicherweise eine Vielzahl von möglichen Zeichen, einschließlich Tabulator und Leerzeichen (oder Leerzeichen), und manchmal auch Form-Feed, vertikale Tabulatoren oder Zeilenumbrüche; und gelegentlich Backspace. –

+0

@ Jonathan Leffler: zumindest versucht er nicht Whitespace zu analysieren (http://compsoc.dur.ac.uk/whitespace/) – ninjalj

Antwort

6

getc und ungetc sind deine Freunde

#include <stdio.h> 

int main(void) { 
    int ch, spaces, x; 
    while (1) { 
    spaces = 0; 
    while (((ch = getc(stdin)) != EOF) && (ch == ' ')) spaces++; 
    if (ch == EOF) break; 
    ungetc(ch, stdin); 
    if (scanf("%d", &x) != 1) break; 
    printf("%d was preceded by %d spaces\n", x, spaces); 
    } 
    return 0; 
} 

Demo bei http://ideone.com/xipm1

Bearbeiten Rahhhhhhhhh ...Ich habe das als C++ hochgeladen. Hier ist das gleiche, aber jetzt C99 strict (http://ideone.com/mGeVk)

+0

scanf, sscanf, fscanf, fgets, bekommt, getc ... lol so viele Optionen. Ich muss auf getc und ungetc nachlesen. Danke für Ihre Antwort. – MykC

+0

+1 weil 'getc()' und 'ungetc()' sind eine bessere Möglichkeit, es zu tun als nur 'scanf()' zu verwenden - aber es entzieht sich der Frage ein wenig. –

+4

@MykC: ** Nein, NICHT bekommt! DONT EVER USE wird, NEVER ** – pmg

1
while (scanf ("%c", &x) == 1) 

Mit %c Sie Leerzeichen lesen können, müssen Sie nur alle Daten und Speicher in einem Array lesen. Ordnen Sie dann char* cptr zu und setzen Sie cptr zum Anfang des Feldes, dann analysieren Sie Ihr Array und wenn Sie Dezimalzahlen lesen möchten, können Sie einfach sscanf auf cptr verwenden, während Sie Dezimal lesen möchten, aber Sie müssen Zeiger in guter Position auf Array (on Nummer, was Sie lesen wany)

if (((*(cptr + 1)) == ' ') && ((*cptr)== ' ')) 
    ya da ya da 
else ((*cptr)== ' ')) 
    ya da ya da 
    sscanf(++cptr, "%d", &x); 
else 
    ya da ya da 
+0

Sieht gut aus. Ich vermeide es, Zeiger und Arrays zu verwenden, wenn ich kann. Hinweis: Ich werde Zeiger und Arrays verwenden, wenn es Sinn macht. – MykC

+0

Ich habe in jemand enses Kommentare erwähnt, dass es scheint, dass, wenn es einen oder mehrere Leerzeichen gab sie alle in einem einzigen Zeichen gespeichert werden, so dass Ihre oben genannten Methode funktioniert. – MykC

0

Was ist Ihre Definition von "White Space"?

Offen gesagt, ich glaube nicht, dass ich versuchen würde, scanf() zu verwenden, um doppelte Leerräume zu identifizieren; Fast jede andere Methode wäre viel einfacher.

Wenn Sie jedoch die nicht unbedingt sinnvoll, auf dem Tun beharren, dann möchten Sie vielleicht Code aus dem folgenden abgeleitet verwenden:

#include <stdio.h> 
#include <string.h> 

int main(void) 
{ 
    int d; 
    char sp[3] = ""; 
    int n; 

    while ((n = scanf("%d%2[ \t]", &d, sp)) > 0) 
    { 
     printf("n = %d; d = %d; sp = <<%s>>", n, d, sp); 
     if (n == 2 && strlen(sp) == 2) 
      printf(" end of group"); 
     putchar('\n'); 
    } 
    return 0; 
} 

Die eckigen Klammern umschließen eine Zeichenklasse und 2, bevor er besteht auf an die meisten 2 Zeichen aus der Klasse. Sie müssen sich möglicherweise darum sorgen, dass Sie die Zeilenumbruch lesen und versuchen, mehr Daten zu erhalten, um die Zeichenklasse zu erfüllen - was durch Entfernen der neuen Zeile aus der Zeichenklasse gelöst werden könnte. Aber dann hängt es von Ihrer Definition von Leerraum ab und davon, ob Gruppen automatisch durch einen Zeilenumbruch enden oder nicht. Es würde nicht schaden, sp[0] = '\0'; am Ende der Schleife zurückzusetzen.

Sie könnten vielleicht besser die Felder umkehren, um zwei Leerzeichen vor einer Zahl zu erkennen. Aber das würde im Normalfall scheitern, also würden Sie auf ein einfaches "%d" Format zurückgreifen, um die Nummer zu lesen (und wenn das fehlschlägt, wissen Sie, dass Sie weder Leerzeichen noch eine Zahl haben - Fehler). Beachten Sie, dass %d führenden Leerzeichen (wie durch den Standard definiert) kaut - alle von ihnen.

Je mehr ich mir das ansehe, desto weniger mag ich 'scanf() nur. Erinnere mich daran, dass ich nicht an deiner Universität einen Kurs abhalte.

+1

Ich glaube, ich muss mich nur mit einem Leerzeichen beschäftigen, das ein einzelner leerer Zeichenschlitz oder ist. Ich bin nicht an scanf gebunden, ich bin nur daran gebunden, es auf die einfachste Weise zu tun, vorausgesetzt, ich musste es wieder tun und nicht nur die Arbeit erledigen. Ich wollte nur sehen, ob es einen Regex-Ausdruck oder einen Trick mit scanf gab, den ich übersehen könnte, der das Problem wirklich leicht lösen würde, da die Eingabe formatiert ist. – MykC

+0

Ich habe Ihre Antwort gesucht und es scheint scanf in Ihrem Beispiel wird immer zurück 2. Ich bin derzeit in welchen Bereich von Werten scanf kann zurück und warum. – MykC

+0

Ich bin korrigiert, es ist nicht immer zurück 2. – MykC

0

Wenn Sie wirklich scanf Typ Funktionalität möchten, können Sie fgets und sscanf, und verwenden Sie die %n Spezifizierer verwenden Scanf zu bekommen Ihr Programm die Offsets für den Anfang und das Ende jedes Leerzeichen Spanne geben es tut den Rest zugleich seiner Arbeit.

Ansonsten, Graben Sie die ganze scanf Familie. Es ist meiner Meinung nach wahrscheinlich der nutzloseste Teil der Standardbibliothek.

+0

Es ist nützlich, aber im Allgemeinen schlecht. Wenn Sie die Eingabe, die einer Debug-Anweisung für das Drucken entspricht, zu einem Programm hinzufügen möchten, ist es großartig. Wenn Sie eine einfache Eingabe für ein Test- oder Demonstrationsprogramm hinzufügen möchten (wo gute Eingabepraktiken nicht das sind, was Sie vorspielen), dann ist es ziemlich gut. Wenn Sie Eingaben für den Produktionscode machen möchten, ist das sehr schlecht. – nategoose

+0

Tatsächlich gibt es eine Verwendung für 'scanf': eine portable Version von' getline' (oder 'getdelim'), einschließlich sauberer Handhabung von eingebetteten NUL-Zeichen, kann mit etwas wie 'scanf ("% 99 [^ \ n] % n ", buf, &cnt);' (wobei 99 durch Ihre Puffergröße ersetzt wird). –

+0

'scanf ("% 99 [^ \ n]% n ", buf, &cnt);' hat das Problem, dass es nichts in 'buf' speichert und 'cnt', wenn die Eingabe mit' '\ n'' beginnt und '' n \' in stdin belässt. Das ist nicht wie 'getline() '. – chux

0

Hier ist eine Lösung, die nur die Funktion scanf() verwendet. Ich verwendete sscanf() in diesem Beispiel für ungefähr die gleiche Funktionalität.

#include <stdio.h> 


int p_1_cnt = 0, p_2_cnt = 0; 

void process_1(int x) 
{ 
    p_1_cnt++; 
} 


void process_2(int x) 
{ 
    p_2_cnt++; 
} 


char * input_line = "1 5 3 2 4 6 2 1 9 0"; 

int main(void) 
{ 
    char * ip = input_line; 

    int x = 0, ws_0 = 0, ws_1 = 0, preceding_spaces = 1, fields = -2; 

    while (sscanf (ip, "%d%n %n", &x, &ws_0, &ws_1) > 0) 
    { 
     ip += ws_0; 

     if ((preceding_spaces) == 1) 
      process_1(x); 
     else 
      process_2(x); 

     preceding_spaces = ws_1 - ws_0; 
    } 

    printf("\np_1_cnt = %d, p_2_cnt = %d", p_1_cnt, p_2_cnt); 
    _fgetchar(); 

    return 0; 
}