MykC
MykC

Reputation: 188

How do I read white space using scanf in c?

Problem: I need to be able identify when two whitespaces occur consecutively.

I have read the following questions:

how to read a string from a \n delimited file

how to read scanf with spaces

And I am aware of scanf problems: http://c-faq.com/stdio/scanfprobs.html

Input will be in the following format:

1 5 3 2  4 6 2  1 9  0

Two white spaces indicates that the next set of data needs to be handle and compared to itself. The length of the line is unknown and the number or integers in each group is unknown. Two whitespaces is the most that will separate the next data set.

While I can use fgets and various built in functions to solve this problem, I am at the point where solving the problem with scanf at this point will likely be easier. However, if that's not the case, using fgets, strtok and atoi will do most of the job but I still need to identify two whitespaces in a row.

The below will take integers until a non-integer is inputed.

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

What I need it do is read whitespaces as well and if there is two consecutive whitespaces I'll the program to do something different with the next set of data.

And once I do get a white space I don't know how to say:

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

I appreciate your time and thank you for your help.

Lesson learned: While a solution for scanf is posted below by Jonathan Leffler, the solution was a bit more straightforward with getc (by way of requiring less intimate knowledge of the inner scanf, regular expressions and char). In retrospect better knowledge of regular expressions, scanf and char would of made the problem easier and of course knowing what functions are available and which one would have been the best one to use from the start.

Upvotes: 9

Views: 30287

Answers (5)

Indinfer
Indinfer

Reputation: 612

Here is a solution that uses only the scanf() function. I used sscanf() in this sample for about the same functionality.

#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;
}

Upvotes: 0

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

What is your definition of 'white space'?

Frankly, I don't think I'd want to try using scanf() to identify double white spaces; nearly every other method would be far easier.

However, if you insist on doing the not desperately sensible, then you might want to use code derived from the following:

#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;
}

The square brackets enclose a character class and the 2 before it insists on at most 2 characters from the class. You might have to worry about it reading the newline and trying to get more data to satisfy the character class - which could be resolved by removing the newline from the character class. But then it hinges on your definition of white space, and whether groups are automatically ended by a newline or not. It wouldn't hurt to reset sp[0] = '\0'; at the end of the loop.

You might, perhaps, be better off reversing the fields, to detect two spaces before a number. But that would fail in the ordinary case, so then you'd fall back on a simple "%d" format to read the number (and if that fails, you know you got neither spaces nor a number - error). Note that %d chews up leading white space (as defined by the standard) - all of them.

The more I look at this, the less I like 'scanf() only. Remind me not to take a class at your university, please.

Upvotes: 0

R.. GitHub STOP HELPING ICE
R.. GitHub STOP HELPING ICE

Reputation: 215547

If you really want scanf type functionality, you can use fgets and sscanf, and use the %n specifier to get scanf to give your program the offsets for the beginning and end of each whitespace span at the same time it does the rest of its work.

Otherwise, ditch the whole scanf family. It's quite possibly the most useless part of the standard library, in my opinion.

Upvotes: 0

pmg
pmg

Reputation: 108986

getc and ungetc are your friends

#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 at http://ideone.com/xipm1

Edit Rahhhhhhhhh ... I uploaded that as C++. Here's the exact same thing, but now C99 strict( http://ideone.com/mGeVk )

Upvotes: 5

Svisstack
Svisstack

Reputation: 16656

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

Using %c you can read whitespace characters, you must only read all data and store in array. Then allocate char* cptr and get set cptr to begin of array, then you analyze your array and if you want read decimal numbers, you can use simply sscanf on cptr while you want read decimal, but you must have pointer in good position on array (on number what you wany read)

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

Upvotes: 1

Related Questions