Use scanf with Regular Expressions
Asked Answered
V

3

8

I've been trying to use regular expressions on scanf, in order to read a string of maximum n characters and discard anything else until the New Line Character. Any spaces should be treated as regular characters, thus included in the string to be read. I've studied a Wikipedia article about Regular Expressions, yet I can't get scanf to work properly. Here is some code I've tried:

scanf("[ ]*%ns[ ]*[\n]", string);

[ ] is supposed to go for the actual space character, * is supposed to mean one or more, n is the number of characters to read and string is a pointer allocated with malloc. I have tried several different combinations; however I tend to get only the first word of a sentence read (stops at space character). Furthermore, * seems to discard a character instead of meaning "zero or more"...

Could anybody explain in detail how regular expressions are interpreted by scanf? What is more, is it efficient to use getc repetitively instead?

Thanks in Advance :D

Vernettaverneuil answered 14/2, 2013 at 11:15 Comment(4)
Try fgets(): fgets(string, sizeof string, stdin);Salim
The problem is that any remaining characters will be left in the input stream, won't they?Vernettaverneuil
If there is enough space fgets() consumes everything up to (and including) a '\n'.Salim
Don't use scanf.Portie
R
5

The short answer: scanf does not handle regular expressions literally speaking.

If you want to use regular expressions in C, you could use the regex POSIX library. See the following question for a basic example on this library usage : Regular expressions in C: examples?

Now if you want to do it the scanf way you could try something like

scanf("%*[ ]%ns%*[ ]\n",str);

Replace the n in %ns by the maximal number of characters to read from input stream. The %*[ ] part asks to ignore any spaces. You could replace the * by a specific number to ignore a precise number of characters. You could add other characters between braces to ignore more than just spaces.

Not sure if the above scanf would work as spaces are also matched with the %s directive.
I would definitely go with a fgets call, then triming the surrounding whitespaces with something like the following: How do I trim leading/trailing whitespace in a standard way?

Recount answered 14/2, 2013 at 20:38 Comment(7)
So, after all, there is no other way to discard any remaining input? I've thought about using getc repetitively, keeping the number of characters I need and discarding the rest of the string until the \n character is found...Vernettaverneuil
I edited my answer at same time you posted your comment. So yes it is possible to ignore some input, but I would not call the scanf format string a "regular expression".Recount
Thanks for your answer! However, can you explain the semantics of what you used there?Vernettaverneuil
Sorry for asking again, but I tested the format string you provided with no results. I tried this Code: #include <stdio.h> int main() { char sth[10], any[1024]; scanf("%*[ ]%9s%*[ ]\n", sth); printf("1%s", sth); getchar(); scanf("%s", any); printf("2%s", any); return 0; } Try using "anything else" as input. You get "12nything" instead of "1anything 2"...Vernettaverneuil
Yeah that's what I thought, I proposed another solution in my answer.Recount
OK! Finally, I decided to use getc instead... Thanks anyway!Vernettaverneuil
@Recount : I'm having trouble for getting the firs nameserver in /etc/resolv.conf using a single fscanf. I've tried fscanf(fp,"%*nameserver:%20[^\n]",address); which return 0 (no result founds); And address is empty. (Yes the file as been successfully opened before with fopen).Entomophilous
S
3

is it efficient to use getc repetitively instead?

Depends somewhat on the application, but YES, repeated getc() is efficient.

Salim answered 14/2, 2013 at 20:41 Comment(0)
B
1

unless I read the question wrong, %[^'\n']s will save everything until the carriage return is encountered.

Birkett answered 1/1, 2016 at 15:57 Comment(1)
The s in %[^'\n']s is not needed.Christianchristiana

© 2022 - 2024 — McMap. All rights reserved.