Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fscanf with character classes

Tags:

c

Say I have a file dog.txt

The quick brown fox jumps over the lazy dog.

I can read from the file like this

# include <stdio.h>
int main(){
  char str[10];
  FILE *fp;
  fp = fopen("dog.txt", "r");
  fscanf(fp, "%[ABCDEFGHIJKLMNOPQRSTUVWXYZ]", str);
  printf("%s\n", str);
  return 0;
}

and the program will output T. However instead of listing all the letters, can I utilize the POSIX Character Classes, something like [:upper:] ?

like image 592
Zombo Avatar asked Jul 13 '26 23:07

Zombo


2 Answers

No, there's no portable way to do it. Some implementations allow you to use character ranges like %[A-Z], but that's not guaranteed by the C standard. C99 §7.19.6.2/12 says this about the [ conversion specifier (emphasis added):

The conversion specifier includes all subsequent characters in the format string, up to and including the matching right bracket (]). The characters between the brackets (the scanlist) compose the scanset, unless the character after the left bracket is a circumflex (^), in which case the scanset contains all characters that do not appear in the scanlist between the circumflex and the right bracket. If the conversion specifier begins with [] or [^], the right bracket character is in the scanlist and the next following right bracket character is the matching right bracket that ends the specification; otherwise the first following right bracket character is the one that ends the specification. If a - character is in the scanlist and is not the first, nor the second where the first character is a ^, nor the last character, the behavior is implementation-defined.

The POSIX.1-2008 description has almost identical wording (and even defers to the ISO C standard in case of accidental conflict), so there are no additional guarantees in this case when using a POSIX system.

like image 63
Adam Rosenfield Avatar answered Jul 15 '26 14:07

Adam Rosenfield


No, you can't. This is what you can do with []:

The conversion specification includes all subsequent bytes in the format string up to and including the matching <right-square-bracket> (']'). The bytes between the square brackets (the scanlist) comprise the scanset, unless the byte after the <left-square-bracket> is a <circumflex> ('^'), in which case the scanset contains all bytes that do not appear in the scanlist between the and the <right-square-bracket>. If the conversion specification begins with "[]" or "[^]" , the <right-square-bracket> is included in the scanlist and the next <right-square-bracket> is the matching <right-square-bracket> that ends the conversion specification; otherwise, the first <right-square-bracket> is the one that ends the conversion specification. If a '-' is in the scanlist and is not the first character, nor the second where the first character is a '^' , nor the last character, the behavior is implementation-defined.

(POSIX standard for scanf. The C standard has similar wording, see Adam Rosenfield's answer.)

So, depending on the implementation, you might be able to do fscanf(fp, "%[A-Z]", str), but there's no guarantee that that will work on any POSIX system. In any case, [:upper:] is the same as [:epru].

like image 40
Fred Foo Avatar answered Jul 15 '26 14:07

Fred Foo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!