C - sscanf not working - c

I'm trying to extract a string and an integer out of a string using sscanf:
#include<stdio.h>
int main()
{
char Command[20] = "command:3";
char Keyword[20];
int Context;
sscanf(Command, "%s:%d", Keyword, &Context);
printf("Keyword:%s\n",Keyword);
printf("Context:%d",Context);
getch();
return 0;
}
But this gives me the output:
Keyword:command:3
Context:1971293397
I'm expecting this ouput:
Keyword:command
Context:3
Why does sscanf behaves like this? Thanks in advance you for your help!

sscanf expects the %s tokens to be whitespace delimited (tab, space, newline), so you'd have to have a space between the string and the :
for an ugly looking hack you can try:
sscanf(Command, "%[^:]:%d", Keyword, &Context);
which will force the token to not match the colon.

If you aren't particular about using sscanf, you could always use strtok, since what you want is to tokenize your string.
char Command[20] = "command:3";
char* key;
int val;
key = strtok(Command, ":");
val = atoi(strtok(NULL, ":"));
printf("Keyword:%s\n",key);
printf("Context:%d\n",val);
This is much more readable, in my opinion.

use a %[ convention here. see the manual page of scanf: http://linux.die.net/man/3/scanf
#include <stdio.h>
int main()
{
char *s = "command:3";
char s1[0xff];
int d;
sscanf(s, "%[^:]:%d", s1, &d);
printf("here: %s:%d\n", s1, d);
return 0;
}
which gives "here:command:3" as its output.

Related

Does C's strtok function support regex?

Let's say I have to parse some phone numbers that can have different delimiters.
Example: 01/555555 01/555-5555
Can I use strtok() in c and give a regex as a delimiter parameter that would include all the different possible delimiters?
No, it does not support regex. Read the documentation before asking. On the other hand, that's precisely how it works so again Read the documentation, i.e. You give it all the possible delimiters.
Check it here
#include <stdio.h>
#include <string.h>
int
main(void)
{
char example[] = "exa$mple#str#ing";
char *token;
char *pointer;
pointer = example;
token = strtok(pointer, "##$");
if (token == NULL)
return -1;
do
{
fprintf(stdout, "%s\n", token);
pointer = NULL;
} while ((token = strtok(NULL, "##$")) != NULL);
}
As a complement to iharob's answer, sscanf may sometimes be an alternative to strtok. Here's an illustration with the given example:
#include <stdio.h>
int main(void) {
const char *s = "01/555555 01/555-5555";
int a, b, c, d, e;
int ret = sscanf(s, "%02d/%d %02d/%d-%d", &a, &b, &c, &d, &e);
if (ret != 5) {
printf("The string is in bad format.\n");
} else {
printf("%02d/%d %02d/%d-%d\n", a, b, c, d, e);
}
return 0;
}
Like strtok, it doesn't support regex but it enables to extract the data within one single line. It works exactly like scanf but it reads from a given string instead of reading from the standard input.
http://linux.die.net/man/3/sscanf

read the characters between special characters in C

I'm new to C language and I need a help on String functions.
I have a string variable called mcname upon which I would like to compare the characters between special characters.
For example:
*mcname="G2-99-77"
I expect the output to be 99 as this is between the - characters.
How can I do this in C please?
Travel the string (walking pointer) till u hit a special character.
Then start copying the characters into seperate array untill u hit the next special character (Place a null character when u encounter the special character second time)
You can do this by using strtok or sscanf
using sscanf:
#include <stdio.h>
int main()
{
char str[64];
int out;
char mcname[] = "G2-99-77";
sscanf(mcname, "%[^-]-%d", str, &out);
printf("%d\n", out);
return 0;
}
Using strtok:
#include <stdio.h>
#include <string.h>
int main()
{
char *str;
int out;
char mcname[] = "G2-99-77";
str = strtok(mcname, "-");
str = strtok (NULL, "-");
out = atoi(str);
printf("%d\n", out);
return 0;
}
sscanf() has great flexibility. Used correctly, code may readily parse a string.
Be sure to test the sscanf() return value.
%2[A-Z0-9] means to scan up to 2 characters from the set 'A' to 'Z' and '0' to '9'.
Use %2[^-] if code goal is any 2 char other than '-'.
char *mcname = "G2-99-77";
char prefix[3];
char middle[3];
char suffix[3];
int cnt = sscanf(mcname, "%2[A-Z0-9]-%2[A-Z0-9]-%2[A-Z0-9]", prefix, middle,
suffix);
if (cnt != 3) {
puts("Parse Error\n");
}
else {
printf("Prefix:<%s> Middle:<%s> Suffix:<%s>\n", prefix, middle, suffix);
}

Using Pointers and strtok()

I'm building a linked list and need your assistance please as I'm new to C.
I need to input a string that looks like this: (word)_#_(year)_#_(DEFINITION(UPPER CASE))
Ex: Enter a string
Input: invest_#_1945_#_TRADE
Basically I'm looking to build a function that scans the DEFINITION and give's me back the word it relates to.
Enter a word to search in the dictionary
Input: TRADE
Output: Found "TREADE" in the word "invest"
So far I managed to come up using the strtok() function but right now I'm not sure what to do about printing the first word then.
Here's what I could come up with:
char split(char words[99],char *p)
{
p=strtok(words, "_#_");
while (p!=NULL)
{
printf("%s\n",p);
p = strtok(NULL, "_#_");
}
return 0;
}
int main()
{
char hello[99];
char *s = NULL;
printf("Enter a string you want to split\n");
scanf("%s", hello);
split(hello,s);
return 0;
}
Any ideas on what should I do?
I reckon that your problem is how to extract the three bits of information from your formatted string.
The function strtok does not work as you think it does: The second argument is not a literal delimiting string, but a string that serves as a set of characters that are delimiters.
In your case, sscanf seems to be the better choice:
#include <stdlib.h>
#include <stdio.h>
int main()
{
const char *line = "invest_#_1945 _#_TRADE ";
char word[40];
int year;
char def[40];
int n;
n = sscanf(line, "%40[^_]_#_%d_#_%40s", word, &year, def);
if (n == 3) {
printf("word: %s\n", word);
printf("year: %d\n", year);
printf("def'n: %s\n", def);
} else {
printf("Unrecognized line.\n");
}
return 0;
}
The function sscanf examines a given string according to a given pattern. Roughly, that pattern consists of format specifiers that begin with a percent sign, of spaces which denote any amount of white-space characters (including none) and of other characters that have to be matched varbatim. The format specifiers yield a result, which has to be stored. Therefore, for each specifier, a result variable must be given after the format string.
In this case, there are several chunks:
%40[^_] reads up to 40 characters that are not the underscore into a char array. This is a special case of reading a string. Strings in sscanf are really words and may not contain white space. The underscore, however, would be part of a string, so in order not to eat up the underscore of the first delimiter, you have to use the notation [^(chars)], which means: Any sequence of chars that do not contain the given chars. (The caret does the negation here, [(chars)] would mean any sequence of the given chars.)
_#_ matches the first delimiter literally, i.e. only if the next chars are underscore hash mark, underscore.
%d reads a decimal number into an integer. Note that the adress of the integer has to be given here with &.
_#_ matches the second delimiter.
%40s reads a string of up to 40 non-whitespace characters into a char array.
The function returns the number of matched results, which should be three if the line is valid. The function sscanf can be cumbersome, but is probably your best bet here for quick and dirty input.
#include <stdio.h>
#include <string.h>
char *strtokByWord_r(char *str, const char *word, char **store){
char *p, *ret;
if(str != NULL){
*store = str;
}
if(*store == NULL) return NULL;
p = strstr(ret=*store, word);
if(p){
*p='\0';
*store = p + strlen(word);
} else {
*store = NULL;
}
return ret;
}
char *strtokByWord(char *str, const char *word){
static char *store = NULL;
return strtokByWord_r(str, word, &store);
}
int main(){
char input[]="invest_#_1945_#_TRADE";
char *array[3];
char *p;
int i, size = sizeof(array)/sizeof(char*);
for(i=0, p=input;i<size;++i){
if(NULL!=(p=strtokByWord(p, "_#_"))){
array[i]=p;//strdup(p);
p=NULL;
} else {
array[i]=NULL;
break;
}
}
for(i = 0;i<size;++i)
printf("array[%d]=\"%s\"\n", i, array[i]);
/* result
array[0]="invest"
array[1]="1945"
array[2]="TRADE"
*/
return 0;
}

Read from line with sscanf, including whitespaces, breaking on other character

I'm sorry for the sloppy title, but I didn't know how to format my question correctly. I'm trying to read a .txt, of which every line has information needed to fill a struct. First I use fgets to read the line, and then i was going to use sscanf to read the individual parts. Now here is where I'm stuck: normally sscanf breaks off parts on whitespaces, but I need the whitespace to be included. I know that sscanf allows ignoring whitespaces, but the tricky part is that I then need some other arbitrary character to separate the parts. For example, I have to break the line
Carl Sagan~Contact~scifi~1997
up into parts for Author,Name,Genre,year. You can see I need the space in Carl Sagan, but I need the function to break off the strings on the tilde character. Any help is appreciated
If your input is delimited by ~ or for instance any specific character:
Use this:
sscanf(s, "%[^~]", name);
[^ is conversion type, that matches all characters except the ones listed, ending with ]
Here is the sample program for testing it:
#include <stdio.h>
int main(int argv, char **argc)
{
char *s = "Carl Sagan~Contact~scifi~1997";
char name[100], contact[100], genre[100];
int yr;
sscanf(s, "%99[^~]~%99[^~]~%99[^~]~%d", name, contact, genre, &yr);
printf("%s\n%s\n%s\n%d\n", name, contact, genre, yr);
return 0;
}
You need strtok. Use ~ as your delimiter.
See the documentation: http://linux.die.net/man/3/strtok
strtok has some drawbacks but it sounds like it will work for you.
EDIT:
After reading this, it sounds like you can use sscanf cleverly to achieve the same result, and it may actually be safer after all.
#include <stddef.h>
#include <string.h>
#include <stdio.h>
char* mystrsep(char** input, const char* delim)
{
char* result = *input;
char* p;
p = (result != NULL) ? strpbrk(result, delim) : NULL;
if (p == NULL)
*input = NULL;
else
{
*p = '\0';
*input = p + 1;
}
return result;
}
int main()
{
char str[] = "Carl Sagan~Contact~scifi~1997";
const char delimiters[] = "~";
char* ptr;
char* token;
ptr = str;
token = mystrsep(&ptr, delimiters);
while(token)
{
printf("%s\n",token);
token = mystrsep(&ptr, delimiters);
}
return 0;
}
Output :-
Carl Sagan
Contact
scifi
1997

sscanf until it reaches a comma

I'm trying to scanf words and numbers from a string looks like: "hello, world, I, 287876, 6.0" <-- this string is stored in a char array (string)
What I need to do is to split things up and assign them to different variables so it would be like
char a = "hello"
char b = "world"
char c = "I"
unsigned long d = 287876
float e = 6.0
I know that regular scanf stops reading from stdin when it reaches a white space. So I've been thinking that there might be a way to make sscanf stop reading when it reaches a "," (comma)
I've been exploring the library to find a format for sscanf to read only alphabet and numbers. I couldn't find such a thing, maybe I should look once more.
Any help?
Thanks in advance :)
If the order of your variables in the string is fixe, I mean It's always:
string, string, string, int, float
the use the following format specifier in sscanf():
int len = strlen(str);
char a[len];
char b[len];
char c[len];
unsigned long d;
float e;
sscanf(" %[^,] , %[^,] , %[^,] , %lu , %lf", a, b, c, &d, &e);
This example using strtok should be helpful:
#include <stdio.h>
#include <string.h>
int main ()
{
char str[] ="hello, world, I, 287876, 6.0" ;
char * pch;
printf ("Splitting string \"%s\" into tokens:\n",str);
pch = strtok (str,",");
while (pch != NULL)
{
printf ("%s\n",pch);
pch = strtok (NULL, ",");
}
return 0;
}
Assuming the format of the text file is constant you can use the following solution.
std::ifstream ifs("datacar.txt");
if(ifs)
{
std::string line;
while(std::getline(ifs,line))
{
/* optional to check number of items in a line*/
std::vector<std::string> row;
std::istringstream iss(line);
std::copy(
std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>(),
std::back_inserter(row)
);
/*To avoid parsing the first line and avoid any error in text file */
if(row.size()<=2)
continue;
std::string format = "%s %s %s %f %[^,] %d";
char year[line.size()],make[line.size()],three[line.size()],full[line.size()];
float numberf;
int numberi;
std::sscanf(line.c_str(),format.c_str(),&year,&make,&three,&numberf,&full,&numberi);
/* create your object and parse the next line*/
}
}
See the documentation for strtok and/or strtok_r

Resources