0
votes

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);
}
3
You've already read the digit character. scanf("%s", person_name); then if(isdigit(person_name[0])) { int num = atoi(person_name); }Weather Vane
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
Oh then put a space in front of " %[^\n]" to filter the leading whitespace.Weather Vane
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
So you needn't bother with removing the trailing newline now.Weather Vane

3 Answers

1
votes

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;
}
1
votes

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.)

0
votes

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.