Related
I have the following .csv file containing information about the song, artist, release year (if specified) and number of listens:
Look What The Cat Dragged In,Poison,,Look What The Cat Dragged In by Poison,1,0,1,0
Nothin' But A Good Time,Poison,1988,Nothin' But A Good Time by Poison,1,1,21,21
Something To Believe In,Poison,1990,Something To Believe In by Poison,1,1,1,1
Talk Dirty To Me,Poison,1978,Talk Dirty To Me by Poison,1,1,1,1
A Salty Dog,Procol Harum,1969,A Salty Dog by Procol Harum,1,1,1,1
A Whiter Shade of Pale,Procol Harum,1967,A Whiter Shade of Pale by Procol Harum,1,1,3,3
Blurry,Puddle of Mudd,2001,Blurry by Puddle of Mudd,1,1,1,1
Amie,Pure Prairie League,,Amie by Pure Prairie League,1,0,4,0
Another One Bites the Dust,Queen,1980,Another One Bites the Dust by Queen,1,1,102,102
Bicycle Race,Queen,1978,Bicycle Race by Queen,1,1,3,3
Kiss You All Over,Kiss,1978,Kiss You All Over by Kiss,1,1,5,5
The name of the file and the desired year should be given as command line arguments, and the program should print all songs from that specific year.
e.g.: ./a.out music.csv 1978
Output:
Talk dirty to me
Bicycle Race
Kiss You All Over
Code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX 300
typedef struct {
char song[101], *artist, *line;
long int year;
} music;
int checkYear(char *word)
{
for (int i = 0; i < strlen(word); i++) {
if (!isdigit(word[i]))
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
FILE *fin = fopen(argv[1], "r");
if (!fin)
{
printf("Error opening the file.\n");
return 1;
}
char buf[MAX];
//int nLines = 0; //count the number of lines
//music *array = NULL;
while( fgets(buf, MAX, fin))
{
buf[strcspn(buf, "\n")] = '\0'; // strip the trailing newline
char *word = strtok(buf, ",");
while (word)
{
//printf("Word is : %s\n", word);
if (checkYear(word))
{
//printf("Year : %s\n", word);
music *array = (music *)malloc(sizeof(music));
char *p;
array->year = strtol(word, &p, 10);
if (array->year == atoi(argv[2]))
{
//printf("Year : %ld\t%d\n", array->year, atoi(argv[2]));
if (scanf("%100[^,]", array->song) == 1)
{
printf("Song : %s\n", array->song);
}
}
}
word = strtok(NULL, ",");
}
}
//printf("I've read %d lines\n", nLines);
fclose(fin);
return 0;
}
So far, it's going decent, I can extract the specified year from each line, but now I just need to print the name of the song from those lines (the first token on the line). I thought about using scanf("%[^,]") to read and print everything up until the first comma but it's just stuck in an endless loop. Could you give me an idea? Thanks in advance!
There are multiple problems in the code:
you do not check that enough arguments were passed on the command line, potentially invoking undefined behavior if not.
you do not need to allocate a music structure: you can just parse the first 3 fields, check the year and output the name of the song directly.
strtok() is inappropriate to split fields from a csv file because it treats a sequence of separators as a single separator, which is incorrect and causes invalid parsing if some fields are empty.
sscanf("%[^,]", ...) will fail to convert an empty field.
To split the fields from the csv line, I recommend you use a utility function that behaves like strtok_r() but tailored for csv lines. A simplistic version will stop on , and \n and replace these with a null byte, returning the initial pointer and updating the pointer for the next field. A more advanced version would also handle quotes.
Here is a modified version:
#include <stdio.h>
#include <string.h>
#define MAX 300
char *get_field(char **pp) {
char *p, *start;
for (p = start = *pp; *p; p++) {
if (*p == ',' || *p == '\n') {
*p++ = '\0';
break;
}
}
*pp = p;
return start;
}
int main(int argc, char *argv[]) {
char buf[MAX];
FILE *fin;
char *filename;
char *select_year;
if (argc < 3) {
printf("Missing arguments\n");
return 1;
}
filename = argv[1];
select_year = argv[2];
fin = fopen(filename, "r");
if (!fin) {
printf("Error opening the file %s.\n", filename);
return 1;
}
while (fgets(buf, sizeof buf, fin)) {
char *p = buf;
char *song = get_field(&p);
char *artist = get_field(&p);
char *year = get_field(&p);
if (!strcmp(year, target_year)) {
printf("%s\n", song);
}
}
fclose(fin);
return 0;
}
regarding: scanf("%[^,]") this consumes (upto but not including) the comma.
So the next instruction needs to be something like getchar() to consume the comma. Otherwise, on the next loop nothing will be read because the first character in stdin is that same comma.
The below code can output what is inside my file. I am trying to find a way to compare if the user input word/character is included in the text file. For instance, if the user writes "r" then, the program finds all the words that have an "r" in the file and output them. After that, I want to replace this word with something, so instead of "r", make it "k". For example, "roadtrip" --> "koadtrip".
The text file has a lot of words line by line , a screenshot of a small part
#define MAX 1024
int main() {
FILE* myFile = fopen("C:\\Users\\Luther\\Desktop\\txtfiles\\words.txt", "r+");
char inputWord[MAX];
char lineBuffer[MAX];
if (myFile1 == NULL)
{
printf("File Does Not Exist \n");
return 1;
}
printf("Enter the word \n");
fgets(inputWord, MAX, stdin);
while (!feof(myFile1))
{
char lineBuffer[1024];
fscanf(myFile1, "%1024[^\n]\n", lineBuffer);
//printf("%s\n", lineBuffer);
while (fgets(lineBuffer, MAX, myFile)) {
if (strstr(lineBuffer, inputWord))
puts(lineBuffer);
}
}
}
I 've managed to make it work and now the program outputs regarding the user input. If a word is the same or part of it is found in the text file, then it prints the word. Look the screenshot below:
Now I am looking for a way to replace the word. For instance, in this specific situation, the word the user inputted is "es" and then all the words that have "es" as a part of them are printed. Is there a way that I can replace for all occasions the "es" and make it "er". Then save the changes in another file without changing anything in the original file.
Here is something to use as a start:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
int main (int argc, char *argv[])
{
FILE *fp = fopen(argc > 1 ? argv[1] : "/etc/motd", "r");
char *line = NULL;
char *p = NULL;
char *needle = argv[2];
char *replace = argv[3];
size_t len = 0;
ssize_t read;
assert(fp);
while ((read = getline(&line, &len, fp)) != -1) {
if (line[0] != '#') {
if ((p = strstr(line, needle))) {
printf("%.*s%s%s", (int)(p - line), line, replace, p+strlen(replace));
} else {
printf("%s", line);
}
}
}
free(line);
fclose(fp);
return 0;
}
Note: this may not handle all edge cases. Also writing back to a file or renaming to
original is left as an exercise :)
Some other starting point
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<regex.h>
#include<sys/types.h>
int main (){
//open file
FILE *file_pointer = fopen("./test_txt.txt", "r");
const char* search_for = "3_hau_gbs";
int line_number = 1;
char* line = NULL;
size_t len = 0;
regex_t regex;
int failed = regcomp(®ex, search_for, REG_EXTENDED);
//You are serching bitwise, so you must first semicompile it
if(failed){
regfree(®ex);
} else {
while(getline(&line, &len, file_pointer) != -1){
//go line after line and check if it include the word you
//you are looking for
int match = regexec(®ex, line, 0, NULL, 0);
if(!match){
//when find so output
printf("%d:%s",line_number, line);
}
line_number++;
}
if(line){
free(line);
}
regfree(®ex);
fclose(file_pointer);
}
}
I have an array of words:
const char *words[3]={cat,dog,snake,bee};
and a txt file like this one:
apple tree day night story bee oil lemons get fight 234 meow woof safari
jazz stuff what is dog fight street snake garden glass house bee question
foot head 29191 43493 ==
(where we don't know how many lines this file has)
I want to check the whole file and each time I find one of the words of the array to print that word and also print the line where it was found.
I'm having trouble with the comparison. My thought was to save every word of the file into an array and compare each one with the words of the words array. But i cannot do that. I have this:
FILE *f;
const char *arr;
f=fopen("test.txt","r");
while(fscanf(f,"%s",arr)!EOF)
I don't really know what to write here so that that I separate the file into words.
Please be kind to me, I'm only trying to learn.
There are several problems in the code snippets you've provided:
const char *words[3]={cat,dog,snake,bee};
Here you declare an array of 3 elements but you have 4 initializers. And you forgot to put the words between quotes.
Here you use fscanf to read into arr, but you didn't allocate memory, arr is not initialized, you probably meant to write char arr[200], 200 being the maximum word length.
FILE *f;
const char *arr;
f=fopen("test.txt","r");
while(fscanf(f,"%s",arr)!EOF)
You want this as base, tough there is still room form improvement:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
const char *words[] = { "cat", "dog", "snake", "bee" };
int main()
{
char line[200]; // maximum line size is 200
size_t len = 0;
FILE *f;
f = fopen("test.txt", "r");
if (f == NULL)
{
printf("Can't open file\n");
return 1;
}
int line_no = 0;
while (fgets(line, sizeof line, f))
{
++line_no;
// (sizeof words)/sizeof *words is the the number of words in the words array
for (int i = 0; i < (sizeof words)/sizeof *words; i++)
{
if (strstr(line, words[i]) != NULL)
{
printf("found %s in line %d\n", words[i], line_no);
}
}
}
fclose(f);
}
You are using fscanf() to read the words out of your file, which is not the best way to do this. You should use getline(3) or fgets(3) to read each line of your file.
Additionally, this line:
const char *words[3]={cat,dog,snake,bee};
Needs to be able to hold 4 char* pointers, not 3. You will also need to include quotes with these string literals. This is another way to do this:
const char *words[] = {"cat", "dog", "snake", "bee"};
Then to get the size of this array, just use sizeof(x) / sizeof(x[0]).
Furthermore, in this code segment:
FILE *f;
const char *arr;
f=fopen("test.txt","r");
while(fscanf(f,"%s",arr)!EOF)
You are using fscanf() on an uninitialized pointer, which leads to many problems. If you wish to use a pointer, you may need to dynamically allocate arr on the heap with malloc(3). If you don't wish to do this, just declare a VLA, such as char arr[200]. Also fscanf() returns number of items scanned, so fscanf(f,"%s",arr)!=EOF will have to be replaced with fscanf(f,"%s",arr)==1, to ensure one word is being read at a time.
Note: You should also check if FILE *f was opened correctly, as it can return NULL on error.
I'm having trouble with the comparison. My thought was to save every word of the file into an array and compare each one with the words of the words array.
As others have mentioned to use strstr(3), another possible option is to use strtok(3) to parse each word on the line, then use strcmp(3) to compare words[i] with the word parsed from the file. If words[] becomes bigger in the future, I would suggest using binary search instead of linear search to compare the words. This will improve you search time from O(n) to O(logn).
Here is some (modified) code I wrote before which does something similar:
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ARRAYSIZE(x) (sizeof x / sizeof x[0])
int main(void) {
const char *words[] = {"cat", "dog", "snake", "bee"};
FILE *fptr;
char *line = NULL, *word = NULL;
const char *delim = " \n";
size_t len = 0, lineno = 0;
ssize_t read;
fptr = fopen("somewords.txt", "r");
if (fptr == NULL) {
fprintf(stderr, "Error reading file\n");
exit(EXIT_FAILURE);
}
while ((read = getline(&line, &len, fptr)) != -1) {
lineno++;
word = strtok(line, delim);
while (word != NULL) {
for (size_t i = 0; i < ARRAYSIZE(words); i++) {
if (strcmp(word, words[i]) == 0) {
printf("Found matched word: %s, Line number: %zu\n", word, lineno);
}
}
word = strtok(NULL, delim);
}
}
free(line);
fclose(fptr);
return 0;
}
Use getline & strstr
char *line = NULL;
size_t len = 0;
ssize_t read;
int line_no = 0;
while ((read = getline(&line, &len, f)) != -1)
{
++line_no;
for (int i = 0; i < 3; i++) {
if (strstr(line, words[i]) != null)
{
// if matched
}
}
}
I need help with this little program I am trying to make.
There is .txt file:
namas house
katinas cat
suo dog
skaicius number
I want to find a line which begins with specific word and then prints second word of that line.
For example, user enters word katinas. Program looks through file, finds line that begins with katinas and finally prints.
What I have so far:
int main()
{
char word;
printf("Enter your word: ");
scanf("%s", &word);
FILE *fp;
fp = fopen("data.txt", "r+");
char buffer[256];
while (fgets(buffer, sizeof buffer, fp) != NULL && atoi(buffer) != word)
;
if (feof(fp))
{
printf(&buffer);
}
fclose(fp);
return 0;
}
Thank you.
There were several mistakes in the code as pointed out elsewhere. This answer will find whole words so for example "suo" but not "su".
#include<stdio.h>
#include<string.h>
int main()
{
char word[256]; // adequate string space (not single char)
char buffer[256];
char *sptr;
FILE *fp;
int found = 0;
printf("Enter your word: ");
scanf("%s", word); // requires a string pointer (note no &)
fp = fopen("data.txt", "r"); // removed "+"
if (fp) {
while (fgets(buffer, sizeof buffer, fp) != NULL) {
sptr = strtok(buffer, " \t\r\n");
if (sptr && strcmp(sptr, word) == 0) {
sptr = strtok(NULL, " \t\r\n");
if (sptr) {
printf("%s\n", sptr);
found = 1;
break;
}
}
}
fclose(fp);
}
if (!found)
printf ("%s not found\n", word);
return 0;
}
You could use a simple logic, just like using a 'for' to search for the word and right after you find the specific word that you want, continue with the 'for' until find a blank space (use ' ' to determinete the end and the beginning of a word) then print out all the letters until find the next blank ' '. This should work just fine.
char word; is a single char which can't store lines; should be an array in order to read a line.
atoi(buffer) != word you are comparing an int (returned by atoi()) with a pointer(array name gets converted into a pointer here). I really don't see the purpose of this.
You don't need to check if end of file has been reached. You just loop through the file line-by-line and check for your string.
Calling printf without format specifier is not safe and you are also passing char (*)[256] whereas printf expects a const char*.
You should also error checking on fopen().
Use a standard prototype for main() such as: int main(void)
After correcting all these, the code would be simplified to:
#include<stdio.h>
#include<string.h>
int main(void)
{
char word[256] = {0};
char buffer[256] = {0};
FILE *fp;
printf("Enter your word: ");
scanf("%s", word);
fp = fopen("data.txt", "r+");
if (!fp) { /* error */}
while ( fgets(buffer, sizeof buffer, fp) )
{
if( strstr(buffer, word) == buffer )
printf("Found: %s\n", buffer);
}
return 0;
}
There's no library function to find if a string "starts with" in C. I am using strstr to achieve that. If there's a match and it's equal to the starting address of the buffer, then it starts with word. Because strstr returns to a pointer to the first match.
#include <stdio.h>
int main(void){
char buffer[256];
char word[256], second_word[256];
char format[256];
FILE *fp;
printf("Enter your word: ");
scanf("%255[A-Za-z]", word);
sprintf(format, "%s %%255s", word);
fp = fopen("data.txt", "r");
while (fgets(buffer, sizeof buffer, fp) != NULL) {
if (sscanf(buffer, format, second_word) == 1) {
printf("%s\n", second_word);
break;//continue;?
}
}
fclose(fp);
return 0;
}
I'm making a program that displays a menu and offers to sort a file using multiple different languages. Currently I have a piece of code that will take in a text file, sort it, and output it to a new text file:
# include <stdio.h>
# include <string.h>
#define MAXNAMELEN 100
#define MAXLINELEN 100
#define MAXITEMS 1000
int main(int argc, char ** argv) {
FILE * infile, * outfile;
// Statically allocated -- dastardly!
char name[MAXNAMELEN];
char line[MAXLINELEN];
char lines[MAXITEMS][MAXLINELEN];
int i, items = 0;
printf("Enter a source filename: ");
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = '\0'; // strip newline
// No error checking -- ANYWHERE -- dastardly!
infile = fopen(name, "r");
while (fgets(line, sizeof(line), infile)) {
strcpy(lines[items], line);
items++;
}
qsort(lines, items, MAXLINELEN, strcmp);
printf("Enter a destination filename: ");
fgets(name, sizeof(name), stdin);
name[strlen(name)-1] = '\0'; // strip newline
outfile = fopen(name, "w");
for (i=0; i<items; i++) {
fputs(lines[i], outfile);
}
fclose(infile);
fclose(outfile);
}
I have the menu part down, but I'm having trouble implementing a way to call a Perl script to sort the file. I want the C program to do the writes to the output file, but the Perl Script to sort it. How can this be achieved? Nasty embedding is what I've found so far..
You can pipe a process with popen and then get the output with fgets:
#include <stdio.h>
#include <stdlib.h>
FILE *popen(const char *command, const char *mode);
int pclose(FILE *stream);
int main(void)
{
FILE *cmd;
char result[1024];
cmd = popen("myperlscript myparams", "r");
if (cmd == NULL) {
perror("popen");
exit(EXIT_FAILURE);
}
while (fgets(result, sizeof(result), cmd)) {
printf("%s", result);
}
pclose(cmd);
return 0;
}