I haven't yet implemented this, I'm still in the thinking stage, but I have to go through a file and replace a certain string with another string. For example,
<img src="/images/logo.gif" ...
should become
<img src="/proxy/www.example.com/images/logo.gif" ...
Any advice on how I can approach this? Perhaps there exist some "string replace" C functions that would do this for me that I don't know about...?
Right now, if I had to write this function myself, I would give it as parameters the file, string to replace, replacement string. Then I would manually go through the file and look for an occurrence of the string and recreate it. This, however, seems very inefficient. Are there better ways to do this?
Thanks,
Hristo
No, there is no function in C that replaces a string throughout a file. You must implement it yourself.
That said, what you're showing us is HTML, and HTML is tricky, because it's hierarchical. Are you required to correctly parse it? Because if you are, the task is much more difficult. Seeing that it's homework, I doubt it, so you might do enough by:
open the file and load it to memory (assuming it isn't too large - if it is, you can write into a temporary file and move it onto the original one after you've finished)
continuously use strstr to find the anchor string you need to start replacing
replace
repeat 2 and 3 until finished with file
write file back
Since it's homework I'm going with the assumption that the string can not span multiple lines. If this assumption is correct (and barring the complications with "replacing text in HTML") then:
1 Read the next line
2 Replace string and write line (to another file)
3 If not at end, goto #1
4 Win \o/
Or perhaps the teacher wants something else shrug
First of all, C is an awesome language, but is one of the most painful languages to do this type of operation in. Just had to say it.
Can you safely assume that the contents of the entire file can fit in memory? If so:
allocate buffer big enough to hold file contents
read entire file into buffer
inputPtr = 0
while(inputPtr < size of buffer) {
replacePosition = strstr(inputPtr, stringToReplace);
if (replacePosition != NULL)
writeUntil = replacePosition - 1
else
writeUntil = end of buffer
write out buffer from inputPtr to writeUntil inclusive (could be 0 bytes)
if (replacePosition == NULL) break
write out the replacement string
inputPtr = replacePosition + strlen(stringToReplace)
}
Since this is homework, I won't give you an answer but I'll point out a classic issue that trips people up.
In C, it's easiest to read a fixed byte count (you can try to do line by line but if a line is too long, that reverts to reading a fixed number of bytes). If the string you are trying to replace ends up getting split between one buffer and a second buffer:
buf1 -> "...<img src=\"/ima"
buf2 -> "ges/logo.gif\"..."
you won't be able to do a simple search replace in memory.
Are you try strcpy function for this,
Assign the url in one string and replace it by strcpy function.
You should investigate the sed command. See what it does and do something similar.
It works as a filter, so when using it to replace something in a file what you often do is capture the output into a file and then replace the old file with the new file.
You can use following program to search & replace string in a file.
int main()
{
.....
replaceIPAddress( "System.cfg", "172.16.116.157", "127.0.0.1");
.....
}
void replaceIPAddress( char * confFileName, char *text_to_find , char *text_to_replace )
{
FILE *input = fopen(confFileName, "r");
FILE *output = fopen("temp.txt", "w");
char buffer[512];
while (fgets(buffer, sizeof(buffer), input) != NULL)
{
char *pos = strstr(buffer, text_to_find);
if (pos != NULL)
{
/* Allocate memory for temporary buffer */
char *temp = calloc(
strlen(buffer) - strlen(text_to_find) + strlen(text_to_replace) + 1, 1);
/* Copy the text before the text to replace */
memcpy(temp, buffer, pos - buffer);
/* Copy in the replacement text */
memcpy(temp + (pos - buffer), text_to_replace, strlen(text_to_replace));
/* Copy the remaining text from after the replace text */
memcpy(temp + (pos - buffer) + strlen(text_to_replace),
pos + strlen(text_to_find),
1 + strlen(buffer) - ((pos - buffer) + strlen(text_to_find)));
fputs(temp, output);
free(temp);
}
else
fputs(buffer, output);
}
fclose(output);
fclose(input);
/* Rename the temporary file to the original file */
rename("temp.txt", confFileName);
}
Related
I have read a lot of questions on this, and using them I have altered my code and have created code which I thought would work.
I think it's my understanding of C, which is failing me here as I can't see where I'm going wrong.
I get no compilation errors, but when I run i receive 'FileReader.exe has stopped working' from the command prompt.
My code is :
void storeFile(){
int i = 0;
char allWords [45440][25];
FILE *fp = fopen("fileToOpen.txt", "r");
while (i <= 45440){
char buffer[25];
fgets(buffer, 25, fp);
printf("The word read into buffer is : %s",buffer);
strcpy(allWords[i], buffer);
printf("The word in allWords[%d] is : %s", i, allWords[i]);
//allWords[i][strlen(allWords[i])-1] = '\0';
i = i + 1;
}
fclose(fp);
}
There are 45440 lines in the file, and no words longer than 25 char's in length. I'm trying to read each word into a char array named buffer, then store that buffer in an array of char arrays named allWords.
I am trying to get this part working, before I refactor to return the array to the main method (which I feel won't be a fun experience).
You are trying to allocate more than a megabyte (45440*25) worth of data in automatic storage. On many architectures this results in stack overflow before your file-reading code even gets to run.
You can work around this problem by allocating allWords statically, like this
static char allWords [45440][25];
or dynamically, like this:
char (*allWords)[25] = malloc(45440 * sizeof(*allWords));
Note that using buffer in the call to fgets is not required, because allWords[i] can be used instead, without strcpy:
fgets(allWords[i], sizeof(*allWords)-1, fp);
Also note that an assumption about file size is unnecessary: you can continue calling fgets until it returns NULL; this indicates that the end of the file has been reached, so you can exit the loop using break.
Alright, so I am working on linux and emacs for the first time using C, and coming from pretty beginner level java programming in eclipse, my new CS course is really daunting. SO much stuff has been thrown at me as if I already knew it...
Anyway, the current part of my assignment I am working on involves reading in text from a file (doing that by piping a text file as standard input into my program). Currently I had three functions, a main function where I read in the file / call other functions, a function that reverses the order of a single word (apple becomes elppa) with *char beg and *char end as parameters, and a function that reverses the order of every word in a line of words, calling the previous function and taking a char *str as a parameter.
I am having trouble reading in the files in my main method in a way that makes it easy to utilize these functions. Here's a snippet of how I am reading them in currently, but as you can see I haven't figured out a way to store a line of words and send that into my function (I need to reverse line by line, so I can't just add every single char to one long array)
enter code here``
char line[8192]
int location = 0;
FILE *in = stdin;
int buff = 0;
while (buff = fgetc(in))
{
fprintf(stderr, "Character is: %d '%c' \n", buff, (char)buff);
if (buff == EOF)
{
break;
}
line[location] = (char)buff;
location++;
}
line[location] = '\0';
If you want to get a whole line, you can do this:
char line[MAX_LINE_SIZE];
fscanf(in, "%[^\n]", line);
//do whatever you need with the line
fscanf(in, "%[\n]", line);
The first fscanf call reads a whole line and store in variable line.
But it doesn't skip that line! If you use it again, it will store the very same line.
The second fscanf call is for this: it stores '\n' in variable line and skips the line you read previously.
If you want, you can create another buffer to get the '\n' and skip the line:
char garbage[2];
fscanf(in, "%[\n]", garbage);
I hope this helps.
The basic gist is, I'm reading words from a text file, storing them as a string, running a function, and then looping over this multiple times, rewriting that string with every new line read. After this loop is done, I need to deal with a different string. The problem is, the second string's bytes, even though I've memset them to 0 at declaration, are getting overwritten by the extra letters in words longer than the space I've allocated to the first string:
char* currDictWord = malloc(9*(sizeof(char));
char* currBrutWord = malloc(9*(sizeof(char));
memset(currBrutWord, 0, 9);
memset(currDictWord, 0, 9);
...
while (stuff) {
fscanf(dictionary, "%s", currDictWord);
}
...
printf("word: %s\n", currBrutWord);
currBrutWord will not be empty anymore. The two ways I've dealt with this are by either making sure currDictWord is longer than the longest word in the dictionary file (kind of a ghetto solution), and doing a new memset on currBrutWord after the loop. Is there no way to tell C to stop writing stuff into memory I've specifically allocated for a different variable?
Yes: stop using fscanf (and preferably the whole scanf-family), and use fgets instead, it lets you pass the maximum number of bytes to read into the variable.
EDIT: (in response to the comment)
fgets will stop reading until count bytes have been read or a newline has been found, which will be in the string. So after fgetsing the string check if there is a newline at the end of it (and remove if necessary). If there is no newline in the string fgetc from the file until you've found one, like this:
fgets(currDictWord, 9, dictionary);
if(currDictWord[strlen(currDictWord) - 1] != '\n'){
while(fgetc(dictionary) != '\n'); /* no body necssary */
/* the stream-pointer is now a the beginning of the next line */
}
Improper string assignment and that not validating data read from a file.
currBrutWord is overrun because too many chars were written into currBrutWord. The same would have happened had you done:
strcpy(currBrutWord, "123456789"); // Bad as this copy 9+1 char into currBrutWord
When using fscanf(), one could limit the data read via:
fscanf(dictionary, "%8s", currDictWord);
This prevents fscanf() from putting too much data into currDictWord. That part is good, but you still have unexpected data coming from the file. You need to challenge any data from the outside world.
if (NULL == fgets(bigbuf, sizeof bigbuf, dictionary)) {
; handle EOF or I/O error
}
// now parse and validate bigbuf using various tools: strtok(), sscanf(), etc.
int n;
if ((sscanf(bigbuf, "%8s%n", currDictWord, &n) < 1) || (bigbif[n] != '\n')) {
; handle error
}
I have managed to read all the lines in my file to a char array but when I want to read a specific line i.e. line 254 as in the example below, I always get the data in the last line in my file. Any idea what's the problem. Thank you.
Here is sample of the code:
while (fgets(line,2000,fp)!=NULL
{
readData [n] = line;
n++;
}
printf ("print line after %s\n",readData [254]);
You're copying the pointer every time. So at the end every entry of the readData array will point to the same memory. Try to copy the data instead:
readData[n] = strdup(line);
And remember to free when done. If you don't have strdup or don't want to use it:
readData[n] = malloc(strlen(line) + 1);
strcpy(readData[n], line);
I'm guessing "readData" is an array of char*s, so when you say readData[n] = line you are always setting the array to the same "buffer" of data.
You need something a bit more like
char buffer[numLines][colsPerLine];
char line[colsPerLine];
while (fgets(line,2000,fp)!=NULL
{
strcpy(buffer[n], line); // copy contents of line into the buffer
n++;
}
printf ("print line after %s\n",buffer[254]);
You can use seek pointer to move cursor to line no . And then apply reading line .
Hope it will work.
The Problem was to find and replace a string in a C File.
I am new to C Files. I have tried the following code but I didnt get any output:
#include<stdio.h>
#include<string.h>
int main()
{
FILE *f1,*f2;
char *src,*dest,*s1,ch,ch1,ch2,ch3;
int i;
f1=fopen("input.txt","rw");
f2=fopen("dummy.txt","rw");
src="mor";
dest="even";
while(ch!=EOF)
{
ch=fgetc(f1);
if(ch==src[0]) //Finding 1st char of src
{
fgets(s1,strlen(src),f1);
if(strcmp(src+1,s1)==0) //Finding occurance of "src" in file
{
fseek(f1,strlen(src)-1,SEEK_CUR);
while(ch1!=EOF) //Copying remaining data into another file
{
ch1=fgetc(f1);
fputc(ch1,f2);
}
fseek(f1,-strlen(src),SEEK_CUR);
for(i=0;i<strlen(dest);i++) //replacing "src" with "dest"
{
ch2=dest[i];
fputc(ch2,f1);
}
fclose(f1);
f1=fopen("input.txt","a");
while(ch3!=EOF) //Appending previosly copied data into 1st file
{
ch3=fgetc(f2);
fputc(ch3,f1);
}
}
}
}
fclose(f1);
fclose(f2);
}
The Contents of input.txt is "morning".
Kindly point the ERROR in the logic and also give an efficient code for the same.
Thanks in Advance.
Reading files in C is usually a bit messy. The first problem that I see is the way ch is used in the main loop. The first time
while (ch != EOF)
is executed, ch is uninitialized, and if it happens to hold EOF, the main loop will not execute at all. I usually use the following structure for reading from files:
FILE *fInput = fopen("input.txt", "r");
int ch; /* need an int to hold EOF */
for (;;)
{
ch = fgetc(fInput);
if (ch == EOF) break;
...
}
In addition, you may need to read up on file pointer concept. For example, after reading the remainder of src, you fseek() forward, and skip some more characters before you copy data to f2. Essentially, you read m, read or (with fgets() - and into an unallocated buffer s1 that would go ka-boom on you some time in the near future), skip 2 more characters (now your pointer is at last n of "morning"), copy "ng" into f2, try to write EOF to f2 in this loop (hence the above pattern for reading until EOF), seek two characters back (which may fail once you reach EOF, my C file functions are a bit rusty these days), write "even" to f1 (which should, if I am wrong about seek after EOF, set input file to "mornieven", and not change it if I am correct). In summary, I don't think the code does what you intend it to do.
I would recommend building up your function. Each one of the following can be written as a program that you should test and finish before going to next step:
read the file safely, and print it out
detect the contents of src, and print the rest of input
save the rest of the input to second file instead of printing
replace src with dest in first file, and ignore the rest (since you open input file with 'rw', this will truncate the rest of input). You may need to do an fseek() to clear the EOF status. Also look at ftell() to record a position that you can jump back to using fseek()
finally, copy in everything you have saved to second file after replacing src with dest (no need to close f1 here. But it is better to open f2 as write, close after copy from first file, and reopen as read to perform the copy back to f1).
In addition, when you need a buffer (such as s1), just use a large enough array for now, but look into malloc() and free() functions to perform dynamic memory allocations for situations like these.
One simple way to do the replace would be to first read in the whole file into a buffer
e.g.
FILE* fpIn = fopen("file.txt","rb");
fseek(fpIn, 0L, SEEK_END);
size_t s = ftell(fpIn);
fseek(fpIn, 0L, SEEK_SET);
void* buf = malloc(s);
fread(buf,s,1,fpIn);
now while writing the file, check for your string
char src[] = "mor";
char dest[] = "even";
int lenSrc = strlen(src);
int lenDest = strlen(dest);
for (char* ch = buf; ch < buf + s; ++ch)
{
if ( !memcmp( ch, src, lenSrc ) )
{
fwrite( dest, 1,lenDest, fpOut );
ch += lenSrc;
}
else
{
fputc( *ch, fp );
}
}
disclaimer: haven't compiled this
You are printing the wrong thing in your output. Print, "ch", not the file pointer.
while(ch!=EOF)
{
ch=getc(f1);
printf("%c",ch);
}
while(ch!=EOF)
{
ch=getc(f2);
printf("%c",ch);
}
Also, f2 is closed at the end during your output. You'll have to reopen it (just like you do with f1.)
At first glance, I see that your code to call fgets is wrong. You have not allocated any memory and you are reading a string into an uninitialized pointer. Read into an array or dynamically allocated memory.
Another problem is that you are declaring ch as char. fgetc() returns an int, and for good reason. It is good to be able to return any possible character or EOF, so EOF shouldn't be a character, so ideally fgetc() returns a bigger type than char.
The upshot is that the loop may well never end, since ch can't possibly hold EOF on some standard implementation. Declare it (and ch1 and ch3) as int.