Parsing a string with scanf - c

I need to get integers from a string that an user enters into the console.
For exemple:
I have this string: [1, 2, 3, 4, 5] and I would like to get all of the integers from it. I already tried multiple scanf patterns, such as scanf("%*[^\[]%d,", &a), but nothing worked. I couldn't find anything relevant on Stack Overflow either.
The main problem is that he can enters between 1 and 50 integers into his string. I have no idea about how to stock only integers (removing ',' and '[' ']' ) into an array.
Some solutions have been found for removing special chars such as [ ] or ,
But now I still need to remove SPACE between comas and integers...
EDIT : problem solved using fgets. I was using scanf to get my string, but it were stopping to SPACES.
Fond out how to do that with scanf :
while(scanf(" %d",&i))

scanf/sscanf does not support regular expressions. You should try something like:
const char my_string[] = "[1,2,3,4,5]";
int a,b,c,d,e;
sscanf(my_string, "[%d,%d,%d,%d,%d]", &a, &b, &c, &d, &e);
Example: http://ideone.com/AOaD7x
It can also be good to check the return value of scanf/sscanf:
int retval = sscanf(my_string, "[%d,%d,%d,%d,%d]", &a, &b, &c, &d, &e);
if (retval != 5)
fprintf(stderr, "could not parse all integers\n");
Reference
Edit:
In your edited question you asks how to do this if there is a variable number of integers. You can use strchr to locate the next comma in the string and continue to iterate until no more comma is found. This assumes that the string ends with ].
const char my_string[] = "[1,2,3,4,5]";
/* start at first integer */
const char *curr = &my_string[1];
while (curr != NULL) {
/* scan and print the integer at curr */
int tmp;
sscanf(curr, "%d", &tmp);
printf("%d\n", tmp);
/* find next comma */
curr = strchr(curr, ',');
/* if a comma was found, go to next integer */
if (curr)
/* warning: this assumes that the string ends with ']' */
curr += 1;
}
Example: http://ideone.com/RZkjWN

Try this piece of code, by using strtok you can separate out all type of unwanted characters in your string. Add all your unwanted set of character to this s array and let strtok do the work.
char str[]="[1,2,3,4,5]";
const char s[4] = "[],"; // All unwanted characters to be filtered out
char *token;
token = strtok(str, s);
while( token != NULL )
{
printf( "%d\n", atoi(token));
token = strtok(NULL, s);
}
Since you have it in the integer format, you could store it in an array and go further with it.
Output :
1
2
3
4
5

Using scanf() for parsing strings is not recommended.
Similarly to others answers, you can use strtok to parse the numbers between "[],", and convert the found numbers using strtol. It would be dangerous to use something like atoi() for integer conversion, as their is no error checking with it. Some more error checking with strtol() can be found in the man page.
Here is some sample(can be improved) code which does this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNUM 50
#define BASE 10
int main(void) {
char string[] = "[1,2,3,4,5]";
char *number, *endptr;
const char *delim = "[],";
int numbers[MAXNUM], current;
size_t i, count = 0;
number = strtok(string, delim);
while (number != NULL) {
current = strtol(number, &endptr, BASE);
/* checking if valid digit found */
/* more error checking can be added */
if (endptr != number) {
numbers[count++] = current;
}
number = strtok(NULL, delim);
}
for (i = 0; i < count; i++) {
printf("numbers[%zu] = %d\n", i, numbers[i]);
}
return 0;
}
Sample input 1:
string[] = "[1,2,3,4,5]";
Output 1:
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
Sample input 2:
string[] = "[1,a,3,c,5]";
Output 2:
numbers[0] = 1
numbers[1] = 3
numbers[2] = 5

Related

Parsing a text file with different types in C

I'm having some trouble when parsing a text file. Each line of the text has a name followed after three float values. All of them are separated by a blankspace. What I want is to store the name in a string and the numbers in an array. I know I have to read each line using fgets and then strtok but the thing is I don't understand how strtok works. Do I have to call strtok four times? How do I assign each "piece" to my variables ?
Thank you for your time!
The strtok will search for the given tokens in a string. You must call it until the it returns NULL.
char *strtok(char *str, const char *delim)
The first call is done passing the string (char*) as the argument str and the remaining times are done passing NULL, as this will define that it should keep looking for the next token from that point onwards.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char line[] = "name 1.45 2.55 3.65";
char* name;
double values[3] = { 0 };
char* ptr = NULL;
int i = 0;
ptr = strtok(line, " "); // Search for the first whitespace
if (ptr != NULL) // Whitespace found
{
/* 'line' is now a string with all the text until the whitespace,
with terminating null character */
name = calloc(1, strlen(line));
strcpy(name, line);
while ((i < 3) && (ptr != NULL))
{
ptr = strtok(NULL, " "); // Call 'strtok' with NULL to continue until the next whitespace
if (ptr != NULL) // Whitespace found
{
/* 'ptr' has now the text from the previous token to the found whitespace,
with terminating null character */
values[i] = atof(ptr); // Convert to double
}
i++;
}
}
printf("%s %lf %lf %lf\n", name, values[0], values[1], values[2]);
}

Pull 10/3 from string and perform the math in C

Could anyone help me figure out how to extract 10/3 from a string, perform the math of 10/3 as a float/double, and store the result? I've tried modifying an older code that I have but I couldn't get it to work. This is that code:
#include<stdio.h>
#include<string.h>
#define SLASH "\\."
int main(void){
char path[100];
printf("Enter file path: \n");
fgets(path, sizeof(path), stdin);
path[strlen(path) - 1] = '\0';
char *token = strtok(path, SLASH);
while(token != NULL){
printf("%s\n", token);
/*Rather than printf the result
I've tried saving the result to
a variable but I could only get
10 to save*/
token = strtok(NULL, SLASH);
}
return 0;
}
I will then be putting the solution into this portion of a larger program:
} else if(j == 6){
arr3[j][(strlen(arr3[j])) - 1] = NULL;
sprintf(temp_arr, "%.18lf", atof(arr3[j]));
strcat(arr3[j], temp_arr);
strcat(arr3[j], new_line);
} else if(j == 7){
I read the following in from a .csv file:
input from file:
The output that I need to obtain is:
Correct output:
Could anyone give me some ideas on how to do this? I've tried to do a for loop instead of a while loop in hopes to save 10 to an array[0] and 3 to an array[1 ], but I would only get array[0] = 10 and array[1 ] = 0. Other times I would just get random junk instead of zero. Using this token approach seemed so straight-forward before but I can't convert for this task. It doesn't seem like this should be so hard for me but I'm stuck. Thanks in advance for any help that anyone can provide.
Edit:
I tweaked the first code to save each separately:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define SLASH "\\."
int main(void){
char path[100];
printf("Enter file path: \n");
fgets(path, sizeof(path), stdin);
path[strlen(path) - 1] = '\0';
char *token = strtok(path, SLASH);
while(token != NULL){
int i = 0;
char temp[100];
strcpy(temp, token);
printf("%s\n", token);
printf("temp = %s\n", temp);
token = strtok(NULL, SLASH);
i++;
}
return 0;
}
From there, I'm trying to implement that into the program that I'm actually working on.
char temp_arr[17];
} else if(j == 6){
arr3[j][(strlen(arr3[j])) - 1] = '\0';
strcpy(temp_arr, arr3[j]);
char *token = strtok(arr3[j], SLASH);
int m = 0;
while(token != NULL){
strcpy(temp_arr2, token);
printf("temp = %s\n", temp_arr2);
token = strtok(NULL, SLASH);
m++;
}
sprintf(temp_arr, "%.18lf", atof(arr3[j]));
strcat(arr3[j], temp_arr);
strcat(arr3[j], new_line);
But I'm getting 10/3 instead of 10 and 3 separately.
There are a number of ways to approach this problem. One of the simplest is to parse the string using the capabilities of strtol which will parse a string for a numeric value, convert the value to a long, and set its endptr parameter to point to one character after the last digit used in the conversion.
(which will be '/' in your case, but you should still check for any intervening spaces between the end of the number and your operator)
You can then start scanning forward from endptr until you locate '/' (or any non-numeric character to use for the operator). Save the character, and advance your pointer by one and call strtol again to convert your final number to long.
Putting the pieces together, you can do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BASE 10
#define EXPR 64
int main (void) {
long a, b;
char op,
expr[EXPR] = "",
*p = expr,
*ep;
printf ("enter expression: ");
if (!fgets (expr, EXPR, stdin)) {
fprintf (stderr, "error: user canceled input.\n");
return 1;
}
a = strtol (p, &ep, BASE); /* convert a to long */
if (p == ep) { /* no digits converted */
fprintf (stderr, "error: strtol - a, no digits found.\n");
return 1;
}
p = ep; /* set p to end-pointer */
while (*p && isspace (*p)) p++; /* skip any intervening spaces */
op = *p++; /* set operator char */
b = strtol (p, &ep, BASE); /* convert b to long */
if (p == ep) { /* no digits converted */
fprintf (stderr, "error: strtol - b, no digits found.\n");
return 1;
}
printf ("%ld %c %ld = ", a, op, b); /* output expression */
switch (op) { /* handle +, -, *, / */
case '+': printf ("%ld\n", a + b); break;
case '-': printf ("%ld\n", a - b); break;
case '*': printf ("%ld\n", a * b); break;
case '/': printf ("%f\n", (double)(a) / b); break;
default : printf ("(error - invalid operator)\n"); break;
}
return 0;
}
(note: you should also check errno following each call to strtol to insure there were no errors, overflow/underflow, etc.. in the conversion. That is left to you)
Example Use/Output
$ ./bin/aexprb
enter expression: 10/3
10 / 3 = 3.333333
$ ./bin/aexprb
enter expression: 10 / 3
10 / 3 = 3.333333
$ ./bin/aexprb
enter expression: 10 + 3
10 + 3 = 13
Look things over and let me know if you have further questions.

Suggestion for parsing values from a particular format

I'm working on a client-server program, where initial step involves parsing the request from client on the server side. The input would look like this.
INSERT A->B B->C; QUERY A B; RESET;
So there are three different commands and they are separated by ';'. RESET option has no parameters. INSERT might have any number of parameter(which are space separated and each value separated by "->"). QUERY is again space separated. The server has to build a acyclic graph based on the input. So my problem is to parse this string into subsequent requests. I planned on using 'strtok' and when the final value is reached(for example 'A'), create a linked list of INSERTS(since the number of request is unknown). But my code is too big and I'm looking for a more concise solution for this problem.
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct insert {
char event1;
char event2;
struct insert * next;
}insert,*insPtr;
typedef struct query {
char event1;
char event2;
struct query * next;
}query,*queryPtr;
typedef struct reset {
int status;
}reset,*rPtr;
void create_node(char *events) {
char event[2];
char *a,*str;
char *pch = strtok(events,"->");
while(pch != NULL) {
printf("%s\n",pch);
pch = strtok(NULL,"->");
}
}
int insert_parser(char *string) {
char *a, *b;
a = string;
b = "INSERT ";
while(*a == *b){
a++;
b++;
}
char *pch = strtok(a," ");
while(pch){
printf("%s\n",pch);
pch = strtok(NULL," ");
}
return(0);
}
int parse_for_values (char* command) {
int value;
if (strstr(command, "INSERT") !=NULL ) {
printf("%s\n",command);
printf ("Insert command found\n");
value = 1;
} else if(strstr(command, "QUERY") !=NULL) {
printf("%s\n",command);
printf ("Query command found\n");
value = 2;
} else if(strstr(command, "RESET") != NULL) {
printf ("Reset command found\n");
printf("%s\n",command);
value = 3;
} else {
printf("unknown command:%s:\n",command);
printf("Unknown command\n");
return(1);
}
switch(value) {
case 1:
insert_parser(command);
break;
case 2:
break;
case 3:
break;
}
return(0);
}
int parse_for_command(char *input) {
char *ptr;
input = strtok(input,"\n");// this strtok is to remove the trailing '\n' in the string
ptr = strtok(input,";");
// printf("%s\n",ptr);
char *cmdPtr;
while(ptr != NULL) {
cmdPtr = ptr;
parse_for_values(cmdPtr);
// printf("%s",ptr);
ptr = strtok(NULL, ";"); //NULL as first argument tells strtok to work on internally held value
}
return(0);
}
int main() {
char input[100];
printf("Enter the input\n");
fgets(input, 100, stdin);
//printf("%s",input);
char *inp = input;
inp = strtok(inp,"\n");
create_node(inp);
//parser(input,"INSERT ", "->");
//parse_for_command(input);
return(0);
}
You have to find individual tokens (lexical analysis) and analyse this sequence of tokens (syntactic analysis). Either you write these procedures manually, or you formally specify syntax of your language and employ existing tools to create the required C code automatically (see flex and bison).
I'm not 100% clear on what you are asking, but the separation of the input commands into individual strings can be done with a single set of calls to strtok. Additionally, the time to remove the trailing newline resulting from the call to fgets is immediately after the call to fgets so you do not have dangling newlines hanging off the end of the string. (e.g.):
fgets(input, 100, stdin);
len = strlen (input); /* get length of str */
if (input[len - 1] != '\n') /* no '\n', input too long */
input[--len] = 0; /* null-terminate */
Separating the strings with strtok can make use of a for loop to handle the initial and subsequent calls to NULL in a single call. For purposes of the example, I've just used a statically declared character array to hold the separated strings, but you can just as well pass p to whatever type list or abstraction you desire. If your intent was to further separate the individual components of each command, then a simple while loop walking a pointer (or two) down the separated INSERT or QUERY command will work. Below is the example, if your intent was different, please let me know.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NCMD 10
#define LCMD 64
int main (void) {
char input[] = "INSERT A->B B->C; QUERY A B; RESET;";
char command[NCMD][LCMD] = {{0}};
char *p = NULL;
size_t i = 0;
size_t ncmd = 0;
for (p = strtok (input, ";"); p; p = strtok (NULL, ";")) {
while (*p == ' ') p++;
strncpy (command[ncmd++], p, LCMD);
}
printf ("\n The separated commands are:\n\n");
for (i = 0; i < ncmd; i++)
printf (" command[%zu] : %s\n", i, command[i]);
printf ("\n");
return 0;
}
Output
$ ./bin/parseinput
The separated commands are:
command[0] : INSERT A->B B->C
command[1] : QUERY A B
command[2] : RESET
Note: the length validation on p as well as the limit check on ncmd were intentionally omitted for purposes of the example.

Parsing house number from street address represented as a char[]

Suppose I have a street address stored as a char[]. Examples of valid values:
1600 Pennsylvania Ave
1 Infinite Loop
221 Baker Street
As you can see, the house number can be of any length.
In C, what is an efficient way of separating the house number into its own int? I'm thinking I need to write a while loop to check for each char c if isdigit(c), but I don't know if I'm on the right track here in terms of implementation.
You can use strtok to break up the string into tokens and use isdigit() to figure out if that token is numeric.
#include <string.h>
#include <stdio.h>
int main()
{
const char str1[80] = "1600 Pennsylvania Ave";
int houseNumber = 0;
const char s[2] = " ";
char *token;
/* get the first token */
token = strtok(str, s);
/* walk through other tokens */
while( token != NULL ) {
printf( " %s\n", token );
if (isdigit(str1[0])) {
houseNumber = atoi (token);
}
token = strtok(NULL, s);
}
return(0);
}
Alternatively, you can use sscanf to read the entire string and automatically parse everything:
#include <string.h>
#include <stdio.h>
int main()
{
const char str1[80] = "1600 Pennsylvania Ave";
int houseNumber = 0;
char streetName[50];
char streetExt[20];
sscanf (str1,"%d %s %s", &houseNumber, streetName, streetExt);
return(0);
}
This last method depends on the format of the strings being exactly the same in all cases, meaning that it's always a number followed by 2 strings. The strtok method will be a little more fault tolerant if there's more other stuff.
Consider the following solution:
#include <stdio.h>
#include <string.h>
int main(void)
{
char address[255];
char * ptr;
int number;
char strnumber[100];
char strstreet[255];
// ask adress
printf("Please, enter the addres: ");
// put end of string replacing newline
fgets(address, 255, stdin);
ptr = strchr(address, '\n');
if(ptr)
{
*ptr = '\0';
}
else
{
address[254] = '\0';
}
// try to read whole number from the beggining of the string
if( 1 == sscanf(address, "%d", &number) )
{
// make number as a string (if it is needed)
sprintf(strnumber, "%d", number);
// take streat to separate string
ptr = strchr(address + strlen(strnumber), ' '); // find the firs space
if( ptr )
{
strcpy(strstreet, ptr + 1); // +1 just to skip the found space
}
}
else
{ // if no number at the beginning of address string
number = 0;
strnumber[0] = '\0';
strstreet[0] = '\0';
}
// show the results
printf("You have entered a string:\n%s\n", address);
printf("The found number is:\n%d\n", number);
printf("The found number as a string:\n%s\n", strnumber);
printf("The address without number is:\n%s\n", strstreet);
}
I would use strstr and atoi like this
char someAddress[80] = "1600 Pennsylvania Ave";
char* p = strstr(someAddress, " ");
if (p)
{
*p = 0; // Terminate string, i.e. cheat for a moment
int number = atoi(someAddress);
*p = " "; // Restore someAddress
}
else
{
// Handle illegal format in someAddress
}
This method shall only be used when you know it is safe to modify someAddress for a short period.
This is one situation with the numbers first, where it is much easier just to use a simple pointer and an if statement to parse the line:
#include <stdio.h>
#define ADDL 64
int main (void) {
char address[ADDL] = {0};
char street[16] = {0};
while (fgets (address, ADDL-1, stdin) != NULL)
{
char *ap = address;
char *sp = street;
while (*ap >= '0' && *ap <= '9') /* while the char is a number */
{
*sp = *ap++; /* copy to street number */
sp++;
}
*sp = 0; /* null-terminate */
printf (" Address: %s Number : %s\n\n", address, street);
}
return 0;
}
Output
$ ./bin/split_address < dat/houses.txt
Address: 1600 Pennsylvania Ave
Number : 1600
Address: 1 Infinite Loop
Number : 1
Address: 221 Baker Street
Number : 221
Note: the printf statement above makes use to the embedded newline at the end of address rather than stripping it as you would normally do. Also note that if you want the number as an integer, long, or unsigned, simply call atoi, strtol or strtoul on street.

c, delete words which contain digits from a string

I need to delete all words that contain digits from the string.
E.g. if input is abdgh 67fgh 32ghj hj dfg43 11 fg, output should be abdgh hj fg.
I thought of using while( text[i] != ' '), but I don't know how to continue it for the rest of the string (after the first whitespace).
I don't have any other idea, and couldn't find anything by googling. Please, help me!
Here, i gave it a try. Works just fine for me. I tried to explain the logic throughout the code via comments. Hope it helps.
#include <stdio.h>
#include <string.h>
int containsNum(char * str);
int main()
{
char str[] = "abdgh 67fgh 32ghj hj dfg43 11 fg"; // input string
char newstr[100] = ""; //new string to create with filtered data
char * pch; //temp string to use in strtok
printf("given string : %s\n",str );
pch = strtok (str," ");
while (pch != NULL)
{
if(!containsNum(pch))// creation of new string with strcat
{ // if the current word not contains any number
strcat(newstr,pch);
strcat(newstr," "); //adding a space between words for readability
}
pch = strtok (NULL, " ");
}
printf("modified string : %s\n", newstr );
return 0;
}
//function containsNum
//gets a string and checks if it has any numbers in it
//returns 1 if so , 0 otherwise
int containsNum(char * str)
{
int i,
size =strlen(str),
flag=0;
for(i=0; i<size ; ++i)
{
if((int)str[i] >=48 && (int)str[i] <=57 ){
flag =1;
break;
}
}
return flag;
}
Regards
Algorithm:
1-You will have to break your input string into smaller components which are also called as tokens. For example: for the string abdgh 67fgh 32ghj hj dfg43 11 fg the tokens could be abdgh, 67fgh, 32ghj, hj, dfg43, 11 and fg.
2- These smaller strings or tokens can be formed using the strtok function which is defined as
char * strtok ( char * str, const char * delimiters );. Thestr in the first argument is the input sting which in the code presented below is string1. The second argument called the delimiters is what actually defines when to divide the input string into smaller pieces(tokens).
For instance, a whitespace as a delimiter will divide the input string whenever a whitespace is encountered, which is how the string is being divided in the code.
3-Since, your program needs to delete those words in the input string which contain digits we can use the isdigit() function to check exactly that.
WORKING CODE:
#include <cstring>
#include <ctype.h>
#include<stdio.h>
int main ()
{
char output[100]="";
int counter;
int check=0; /* An integer variable which takes the value of "1" whenever a digit
is encountered in one of the smaller strings or tokens.
So, whenever check is 1 for any of the tokens that token is to be ignored, that is,
not shown in the output string.*/
char string1[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
char delimiters[] = " ";//A whitespace character functions as a delimiter in the program
char * token;//Tokens are the sub-strings or the smaller strings which are part of the input string.
token=strtok(string1,delimiters);/*The first strktok call forms the first token/substring which for the input
given would be abdgh*/
while(token!=NULL)/*For the last substring(token) the strtok function call will return a NULL pointer, which
also indicates the last of the tokens(substrings) that can be formed for a given input string.
The while loop finishes when the NULL pointer is encountered.*/
{
for(counter=0;counter<=strlen(token)-1;counter++)/*This for loop iterates through each token element.
Example: In case of abdgh, it will first check for 'a',
then 'b', then 'd' and so on..*/
{
if(isdigit((int)token[counter])>0)/*This is to check if a digit has been encountered inside a token(substring).
If a digit is encountered we make check equal to 1 and break our loop, as
then that token is to be ignored and there is no real need to iterate
through the rest of the elements of the token*/
{
check=1;
break;
}
}
if(check==1) /* Outside the for loop, if check is equal to one that means we have to ignore that token and
it is not to be made a part of the output string. So we just concatenate(join) an
empty string ( represented by " " )with the output string*/
{
strcat(output,"");
check=0;
}
else /*If a token does not contain any digit we simply make it a part of the output string
by concatenating(joining) it with the output string. We also add a space for clarity.*/
{
strcat(output,token);
strcat(output," ");
}
token = strtok( NULL, delimiters ); /*This line of code forms a new token(substring) every time it is executed
inside the while loop*/
}
printf( "Output string is:: %s\n", output ); //Prints the final result
return 0;
}
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
char *filter(char *str){
char *p, *r;
p = r = str;
while(*r){
char *prefetch = r;
bool contain_digit = false;
while(!isspace(*prefetch) && *prefetch){
if(contain_digit)
++prefetch;
else if(isdigit(*prefetch++))
contain_digit = true;
}
if(contain_digit){
r = prefetch;
}else {
while(r < prefetch){
*p++ = *r++;
}
}
if(!*r)
break;
if(p[-1] == *r)
++r;
else
*p++ =*r++;
}
*p = '\0';
return str;
}
int main(void) {
char text[] = "abdgh 67fgh 32ghj hj dfg43 11 fg";
printf("%s\n", filter(text));//abdgh hj fg
return 0;
}

Resources