0

I have input like the following:

Someting sth
example
 5  15   
3

I want to scanf input by lines to get whole content of the line. But when reaching first digit (there can be spaces/tabs before it) I want to scanf it as int.

That's what I have come up with but it does not work as expected - cursor still does not stop at digit character.

char person_name[1000];
int n;

while (scanf("%[^\n/D]%*c", person_name) > 0) {
    if (checkIfContainsNumber(person_name) == 0) {
      appendToLinkedList(&head_ref, person_name);
    } else {
      break;
    }
}

while (scanf("%d", &n) > 0) {
    printf("%d ", n);
}
Epsilon47
  • 768
  • 1
  • 13
  • 28
  • You've *already read* the digit character. `scanf("%s", person_name);` then `if(isdigit(person_name[0])) { int num = atoi(person_name); }` – Weather Vane Oct 18 '19 at 10:16
  • Yeah but if I use `scanf("%s", person_name);` then I read words by words and not by line. I need to distinguish if there are more words in the same line. – Epsilon47 Oct 18 '19 at 10:18
  • 1
    Oh then put a space in front of `" %[^\n]"` to filter the leading whitespace. – Weather Vane Oct 18 '19 at 10:19
  • I have tried to edit the regex a bit so my final regex looks like: `scanf(" %[^\n^0-9]%*c", person_name)` - the space in front of `%` helped. Thanks a lot. – Epsilon47 Oct 18 '19 at 10:32
  • So you needn't bother with removing the *trailing* newline now. – Weather Vane Oct 18 '19 at 10:33
  • So in your example, should the linked list contain {5, 15, 3} after scanning the input? – M Oehm Oct 18 '19 at 10:42
  • @MOehm sorry if I was not clear. No, the items which I want to be in linked list have to be present before numbers. If the first number is present I want to scanf into another variable and break the `while`. – Epsilon47 Oct 18 '19 at 10:45
  • Ah, so you want to change the scanning mode from strings to numbers once you have read a line that begins with a number. – M Oehm Oct 18 '19 at 10:47
  • @MOehm yes exactly - but I need to scanf lines as whole line before the numbers. – Epsilon47 Oct 18 '19 at 10:49
  • Short answer: Don't try to use `scanf` as your primary inut method. There's no `scanf` format that means "read either a string or an integer so I can do two different things, depending". See [here](https://stackoverflow.com/questions/58403537/what-can-i-use-to-parse-input-instead-of-scanf) for alternatives. – Steve Summit Oct 18 '19 at 13:29

3 Answers3

1

As far as I understand the problem, each line could be considered either as a sequence of names or a sequence of integers.
So I would try to read the file line by line and analyse each extracted line as one sequence or another (spaces are implicitly consumed).
The trick here is the usage of "%n" to go further in the analyse of the same line.

#include <stdio.h>

int
main(void)
{
  FILE *input=fopen("input.txt", "r");
  if(!input)
  {
    return 1;
  }
  char line[1024];
  while(fgets(line, sizeof(line), input))
  {
    int pos=0;
    int value, count;
    char name[256];
    if(sscanf(line+pos, "%d%n", &value, &count)==1)
    {
      pos+=count;
      printf("a line with values: <%d>", value);
      while(sscanf(line+pos, "%d%n", &value, &count)==1)
      {
        pos+=count;
        printf(" <%d>", value);
      }
      printf("\n");
    }
    else if(sscanf(line+pos, "%255s%n", name, &count)==1)
    {
      pos+=count;
      printf("a line with names: <%s>", name);
      while(sscanf(line+pos, "%255s%n", name, &count)==1)
      {
        pos+=count;
        printf(" <%s>", name);
      }
      printf("\n");
    }
  }
  fclose(input);
  return 0;
}
prog-fh
  • 13,492
  • 1
  • 15
  • 30
1

Read the input line-wise with fgets and keep a mode: TEXT for text, NUMBER for numbers and ERROR for an error condition. (The error condition is undescribed. It could occur when you encounter non-numeric data in NUMBER mode, for example.)

Start out with TEXT. Before processing a line in text mode, check whether it could be a digit by a simple sscanf into the line. If you can read a number, switch to number mode, where you scan all numbers from a line.

char line[80];
enum {TEXT, NUMBER, ERROR = -1} mode = TEXT;

while (mode != ERROR && fgets(line, sizeof(line), stdin)) {
    if (mode == TEXT) {
        int n;

        if (sscanf(line, "%d", &n) > 0) mode = NUMBER;
    }

    if (mode == TEXT) {
        line[strcspn(line, "\n")] = '\0';
        process_string(line);
    } else if (mode == NUMBER) {
        char *p = line;
        char *end;
        int n = strtol(p, &end, 0);

        if (end == p) mode = ERROR;

        while (end > p) {
            process_number(n);
            p = end;
            n = strtol(p, &end, 0);
        }            
    }
}

(But this approach will fail if the numbers are all in one very long. fgets truncates the input so that the specified size will nor be exceeded.)

M Oehm
  • 28,726
  • 3
  • 31
  • 42
0

Consider changing the scan strategy - ignore all characters that are non-digit, and then read the integer from that digits forward

if ( scanf("%*[^0-9]%d", &n) == 1 ) { ... }

The first field '%*[...]' will skip over anything that is non-digit. Note that it's possible to reach EOF before finding a digit - if statement is needed to check.

dash-o
  • 13,723
  • 1
  • 10
  • 37