7

The problem: I am attempting to use scanf to read a sentence with fields seperate by | ,so naturally i use the scanf's natural features to ignore this symbol but it then also ignores everything that has a | in it.

The code, simplified:

int main(){
    char* a=malloc(8);
    char* b=malloc(8);
    scanf("%s | %s",a,b);
    printf("%s %s",a,b);
}

when i attempt the input:

TEST | ME

it works as intended, but when i have the following case:

TEST ME|

it naturally reads the test, but ignores the ME|, is there any way around this?

Thongurf
  • 105
  • 1
  • 1
  • 6
  • 1
    `%s` doesn't do what you think it does. In general, `scanf()` doesn't do what you expect it to do either. Better use saner functions like `strtok_r()` or `strchr()`. –  Jun 21 '13 at 04:40

5 Answers5

18
    scanf("%[^ \t|]%*[ \t|]%[^ \t\n|]", a,b);
    printf("%s %s",a,b);

Annotation:

%* : ignore this element.

E.g. %*s //skip the reading of the text of this one

%[character set(allow)] : Read only character set that you specify.

E.g. %[0123456789] or %[0-9] //Read as a string only numeric characters

%[^character set(denied)] : It is to mean character other than when ^ is specified at the beginning of the character set.

BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
1

Yes, you can scan for a character set. The problem you're seeing is not related to the vertical bar, it's the fact that a string stops at the first whitespace character, i.e. the space between "TEST" and "ME|".

So, do something like:

if(scanf("%7[^|] | %7[^|]", a, b) == 2)
{
  a[7] = b[7] = '\0';
  printf("got '%s' and '%s'\n", a, b);
}

See the manual page for scanf() for details on the [ conversion specifier.

unwind
  • 391,730
  • 64
  • 469
  • 606
1

This one should work.

char a[200], b[200];

scanf ("%[^|]| %[^\n]", a, b);  // Use it exactly
printf ("a = %s\nb = %s\n", a, b);

Meaning of this formatting. I seperate the format string into 3 parts and explain.

"%[^|]" - Scan everything into 1st string, until the bar character('|') appears.

"| " - Read the '|' and ignore it. Read all white space characters and ignore them.

"%[\n]" - Read remainder of the line into the 2nd string.

Test case

first string is         this | 2nd is this
a = first string is     this
b = 2nd is this

no space|between bar
a = no space
b = between bar
sukumarst
  • 265
  • 1
  • 5
0

Leading spaces can be truncated by using extra local variable to store leading spaces.

%[ ] needs to be mentioned in scanf to store leading spaces

"%[ ]%[^\n]",first_string,second_string , mentioned scanf format specifier is to read two strings .

 first_string contains leading spaces from given input string
 second_string contains actual data without leading spaces.

Following is the sample code

int main()
{

  char lVar[30];
  char lPlaceHolder[30];

  printf("\n Enter any string with leading spaces : ");
  memset(lVar,'\0',30);
  memset(lPlaceHolder,'\0',30);

  scanf("%[ ]%[^\n]",lPlaceHolder,lVar);

  printf("\n lPlaceHolder is :%s:\n",lPlaceHolder);
  printf("\n lVar is :%s:\n",lVar);
  return(0);
}

Input:

" hello world"

Output:

lPlaceHolder is : :

lVar is :hello world:

Note: Space not displayed properly for lPlaceHolder after uploading to stackover flow website

Community
  • 1
  • 1
Praveen
  • 1
  • 2
-1

I'd say instead of messing with scanf(), try using saner functions - those that work as per the (intuitive) expectations:

char s1[] = "FOO | BAR";
char s2[] = "FOO BAR |";

void print_sep(char *in)
{
    char *endp;
    char *sep = strtok_r(in, "|", &endp);
    printf("%s\n", sep);
    if (sep = strtok_r(NULL, "|", &endp))
        printf("%s\n", sep);
}

print_sep(s1);
print_sep(s2);