sscanf to get segment of string surrounded by two fixed strings - c

I'm trying to remove the extension of a file (I know it is .txt) using sscanf(). I've tried with many format strings I think may work, but with no success. The main problem is that I just can't understand sscanf()'s documentation, so I don't get how to use this [=%[*][width][modifiers]type=] I've tried to tell it that end must be ".txt" or to save initial string in a variable and a %4ccorresponding to the extension in another one, but again… can't make it work.
I know this has been asked before here: sscanf: get first and last token in a string but as I said... I don´t understand its solution.
The part of my code that does that:
sscanf(fileName,"the_sender_is_%s%*[.txt]", sender);
The input file name is, for example: "the_sender_is_Monika.txt"
In sender I should have
Monika
but whatever I try gives me
Monika.txt

When you use
sscanf(fileName,"the_sender_is_%s%*[.txt]", sender);
The function reads as much as it can with %s before it processes %*[.txt].
Use
sscanf(fileName,"the_sender_is_%[^.]", sender);

While sscanf() is powerful, it is not the universal tool. There are limits on what you can do with it, and you're hitting them. A moderate approximation to the task would be:
char body[32];
char tail[5];
if (sscanf("longish-name-without-dots.txt", "%31[^.]%4s", body, tail) != 2)
…oops — can't happen with the constant string, but maybe with a variable one…
This gets you longish-name-without-dots into body and .txt into tail. But it won't work all that well if there are dots in the name part before the extension.
You're probably looking for:
const char *file = "longish-name.with.dots-before.txt";
char *dot = strrchr(file, '.');
if (dot == NULL)
…oops — can't happen with the literal, but maybe with a variable…
strcpy(tail, dot); // Beware buffer overflow
memcpy(body, file, dot - file);
body[dot - file] = '\0';

Related

Need help parsing a "|" seperated line from a file

I have to parse a file that would look something like this
String|OtherString|1234|0
String2|OtherString2|4321|1
...
So, I need to go through every line of the file and take each seperate token of each line.
FILE *fp=fopen("test1.txt","r");
int c;
char str1[500];
char str2[500];
int num1=0;
int num2;
while((c=fgetc(fp))!=EOF){
fscanf(fp, "%s|%s|%d|%d", &str1[0], &str2[0], &num1, &num2);
}
fclose(fp);
There's more to it, but these are the sections relevant to my question. fscanf isn't working, presumably because I've written it wrong. What's supposed to happen is that str1[500] should be set to String, in this case, str2 to OtherString, etc. It seems as though fscanf isn't doing anything, however. Would greatly appreciate some help.
EDIT: I am not adamant about using fgetc or fscanf, these are just what I have atm, I'd use anything that would let me do what I have to
strtok() in a loop will work for you. The following is a bare bones example, with very little error handling etc, but illustrates the concept...
char strArray[4][80];
char *tok = NULL;
char *dup = strdup(origLine);
int i = 0;
if(dup)
{
tok = strtok(dup, "|\n");
while(tok)
{
strcpy(strArray[i], tok);
tok = strtok(NULL, "|\n");
i++;
}
free(dup);
}
If reading from a file, then put this loop inside another while loop that reads the file, line by line. Functions useful for this will include fopen(), fgets() and fclose(). One additional feature that should be considered for code that reads data from a file is to determine the number of records (lines) in the file to be read, and use that information to create a properly sized container with which to populate with the parsing results. But this will be for another question.
Note: fgetc() is not suggested here as it reads one char per loop, and would be less efficient than using fgets() for reading lines from a file when used in conjunction with strtok().
Note also, in general, the more consistently a file is formatted in terms of number of fields, content of fields, etc. the least complicated a parser needs to be. The inverse is also true. The less consistently formatted input file requires a more complex parser. For example, for human entered line data, the parser required is typically more complicated than say one used for a computer generated set of uniform lines.

Find specific file in folder and edit it

I am really new to C, so maybe the question is too easy or not relevant. But I didn't find answer to this question.
I have folder with files which named as: -90.txt, -89.txt, ..., 0.txt, 1.txt, 2.txt, ..., 90.txt.
I need to have some function which will receive number (folder name) as an argument and open that file.
function editFile(number){
fp=fopen("/data/" + number + ".txt", "wr");
...
// do some other things
}
In C you do not have flexibility to add a number to a string. If you want to append a number to a string then first you have to convert it into a string using itoa function. You can find online documentation about that function.
And here is general outline how would you add a number to string in C
First convert the number into string (store it in a new buffer of type char[]) using itoa or sprintf
Then make a new buffer of type char[]. Make sure you create it of enough size so that it can hold complete file path.
Then use strcat to append the two strings.
Instead of all the above process, you can also use sprintf.
Then you can pass the result to fopen
C doesn't have strings with the idea of concatenation. So if you want to concatenate strings you have to use functions like this:
function editFile(char* number)
{
char pathName[MAX_PATH];
strcpy(pathName, "/data/");
strcat(pathName, number);
strcat(pathName, ".txt");
fp=fopen(pathName, "wr");
...
// do some other things
}
You can utilize sprintf to make it shorter. But you should add security checks because you have the risk of buffer overrun. Hint: strcpy_s, strccat_s, sprintf_s. (But this' beyond the answer to your question.)
In C you cannot build a string in that way. Use sprintf to create the file name in a local variable.
char filename[1024];
sprintf(filename, "/data/%d.txt", number); // assume that a signed value comes from `int`
fp = fopen(filename, "w+"); // replaced "wr"
You are probably used to high level languages where you can "build" a string by concatenating integers, floats, other strings, etc. to it. This doesn't work in C.
As commented #WeatherVane pointed out, the sprintf function is the right tool for the job:
char buffer[PATH_MAX]; // assuming POSIX
sprintf(buffer, "/data/%d.txt", number);
fp = fopen(buffer, "wr");

How to read a data point from a text file in C

I have a text file full of points of the following format on different lines
LONG,LONG
i can successfully read each line and print it out, but I how can I parse the string in C such that I get each long of each point on its own?
Thanks!
if you have the line already, it's easiest to use sscanf() to do this:
long a, b;
if(sscanf(line, "%ld,%ld", &a, &b) == 2)
{
/* Successfully parsed two long integers, now store them somewhere I guess. */
}
Note that it's a good idea to check the return value of sscanf(), this protects you from wrongly accepting illegal data and getting undefined results.
You can do it in multiple steps too if you need more control, as #dasblinkenlights suggested. You can use strtol() to parse the first number from the start of the line, then if that succeeds look for the comma, and then parse the second number. It can be faster than sscanf(), but I wouldn't expect too much for something this simple.
There are many solutions to this.
One is to read the line, read the first long with strtol find the position of the comma that follows with strchr, and read the second number from there.
Another solution would be to read the line, and pass it to sscanf function with the format that accepts two comma-separated LONGs.
Use the string variant of scanf() if you say you've already got the line:
char* line;
long long1;
long long2;
sscanf(line, "%ld,%ld", &long1, &long2);
Indeed as #unwind suggests in his +1 answer, it's a very good idea to check the return value of scant(), which is the number of successfully read values.

Reading and comparing numbers from txt file C

I am new to C programming, so I am having difficulties with the problem below.
I have a text file inp.txt which contains information like the following:
400;499;FIRST;
500;599;SECOND;
670;679;THIRD;
I need to type a number and my program needs to compare it with numbers from the inp.txt file.
For example, if I type 450, it's between 400 and 499, so I need write to the word FIRST to the file out.txt
I have no idea how to convert a character array to an int.
I think you'll want these general steps in your program (but I'll leave it to you to figure out how you want to do it exactly)
Load each of the ranges and the text "FIRST", "SECOND", etc. from the file inp.txt, into an array, or several arrays, or similar. As I said in the comment above, fscanf might be handy. This page describes how to use it - the page is about C++, but using it in C should be the same http://www.cplusplus.com/reference/clibrary/cstdio/fscanf/. Roughly speaking, the idea is that you give fscanf a format specifier for what you want to extract from a line in a file, and it puts the bits it finds into the variables you specify)
Prompt the user to enter a number.
Look through the array(s) to work out which range the number fits into, and therefore which text to output
Edit: I'll put some more detail in, as asker requested. This is still a kind of skeleton to give you some ideas.
Use the fopen function, something like this (declare a pointer FILE* input_file):
input_file = fopen("c:\\test\\inp.txt", "r") /* "r" opens inp.txt for reading */
Then, it's good to check that the file was successfully opened, by checking if input_file == NULL.
Then use fscanf to read details from one line of the file. Loop through the lines of the file until you've read the whole thing. You give fscanf pointers to the variables you want it to put the information from each line of the file into. (It's a bit like a printf formatting specifier in reverse).
So, you could declare int range_start, range_end, and char range_name[20]. (To make things simple, let's assume that all the words are at most 20 characters long. This might not be a good plan in the long-run though).
while (!feof(input_file)) { /* check for end-of-file */
if(fscanf(input_file, "%d;%d;%s", &range_start, &range_end, range_name) != 3) {
break; /* Something weird happened on this line, so let's give up */
else {
printf("I got the following numbers: %d, %d, %s\n", range_start, range_end, range_name);
}
}
Hopefully that gives you a few ideas. I've tried running this code and it did seem to work. However, worth saying that fscanf has some drawbacks (see e.g. http://mrx.net/c/readfunctions.html), so another approach is to use fgets to get each line (the advantage of fgets is that you get to specify a maximum number of characters to read, so there's no danger of overrunning a string buffer length) and then sscanf to read from the string into your integer variables. I haven't tried this way though.

parsing space separated text in C

I'm writing a program for a school project that is supposed to emulate the Unix shell, in a very basic form. It's basically parsing input, then doing a fork/exec. I need to be able to read arguments in the program (not as arguments passed to the program from the command line) individually. For example, I will prompt:
Please enter a command:
...and I need to be able to parse both...
ls
OR
ls -l
but the trouble is that there seems to be no easy way to do this. scanf() will pull each argument individually, but I see no way to place them into differing slots in a char* array. For example, if I do...
char * user_input[10];
for (int i=0; i<10; i++){
user_input[i] = (char *) malloc(100*sizeof(char));
}
for (int i=0; *(user_input[i]) != '#'; i++)
{
scanf("%s", user_input[index]);
index++;
}
...then user_input[0] will get "ls", then the loop will start over, then user_input[0] will get "-l".
gets and fgets just take the whole line. Obviously this problem can be logically solved by going through and plucking out each individual argument...but I'd like to avoid having to do that if there is an easy way that I'm missing. Is there?
Thanks!
If your use case is simple enough, you can do this with strtok:
char *strtok(char *str, const char *delim);
char *strtok_r(char *str, const char *delim, char **saveptr);
The strtok() function parses a string into a sequence of tokens. On the first call to strtok() the string to be parsed should be specified in str. In each subsequent call that should parse the same string, str should be NULL.
You can use strtok or strtok_r to split the string on spaces.
If you're doing something more complex, where some of the arguments could have (quoted) spaces in them, you're pretty much stuck parsing it yourself - though you could have a look at the source of a shell (e.g. bash) to see how it handles it.
kilanash helpfully reminds me of my obvious omission - GNU getopt. You'll still have to have parsed into separate arguments yourself first, though.
Forget that scanf exists for it rarely does what you want. Get the whole line at once and then write code to split it up. strtok - the second most favored answer to this question - is also problem ridden.
You can use strtok_r to break the string up on whitespace. Note that it is a destructive operation (modifies the input string).
Try to see if anything of this will help you:
ANSI C Command Line Option Parsing Library
The Argtable Homepage
Regards,
Tiho

Resources