Beginner
Beginner

Reputation: 105

Replace each line in a text file using C

I want to capitalise every other word in poem.txt, starting from each line. I made a function capitalise() that receives a string (eg: "a lonely number like root three"), capitalises every other word and returns it (eg: returns "A lonely Number like Root three" ). I'm trying to read each line from poem.txt, send that line to capitalise() and then receive the updated string and replace that line with the updated string but I can't figure out how. I tested my program, it can read the contents of the file and send them to capitalise() and display line by line but it can't write and replace each line. I tried using fprintf() but it's not working. Can you guys enlighten me?

poem.txt(before execution)
i fear that I will always be
a lonely number like root three
the three is all that’s good and right,
why must my three keep out of sight
beneath the vicious square root sign,
I wish instead I were a nine
for nine could thwart this evil trick,
with just some quick arithmetic
i know I’ll never see the sun, as 1.7321
such is my reality, a sad irrationality
when hark! What is this I see,
another square root of a three
has quietly come waltzing by,
together now we multiply
to form a number we prefer,
rejoicing as an integer
we break free from our mortal bonds
with the wave of magic wands
our square root signs become unglued
your love for me has been renewed

Code:

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

int reverse(int otherWord)
{
    if (otherWord)
        return 0;
    else
        return 1;
}
void capitalise(char *s)
{
     int start = 1;
     int otherWord = 1;
     for (; *s; s++)
     {
            if (start && otherWord)
                *s = toupper(*s);
            start = isspace(*s);
            if (start)
                otherWord = reverse(otherWord);

     }
}
int main(int argc, char *argv[])
{
    FILE * fp;
    char * line = NULL;
    size_t len = 0;
    ssize_t read;

    fp = fopen("poem.txt", "r+");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    while ((read = getline(&line, &len, fp)) != -1) {
        capitalise(line);
        fprintf(fp, "%s", line); // Here's the problem, this line!

    }

    fclose(fp);
    if (line)
        free(line);
    exit(EXIT_SUCCESS);
}

poem.txt (after execution):
i fear that I will always be
I fear That I Will always Be
ee
Ee
three is all that’s good and right,
three Is all That’s good And right,
eath the vicious square root sign,
Eath the Vicious square Root sign,
ne could thwart this evil trick,
Ne could Thwart this Evil trick,
know I’ll never see the sun, as 1.7321
know I’ll never See the Sun, as 1.7321
en hark! What is this I see,
En hark! What is This I See,
e
E
s quietly come waltzing by,
S quietly Come waltzing By,
form a number we prefer,
Form a Number we Prefer,
e break free from our mortal bonds
E break Free from Our mortal Bonds
uare root signs become unglued
Uare root Signs become Unglued
edEd

poem.txt(expected execution):
I fear That I Will always Be
A lonely Number like Root three
...

Upvotes: 0

Views: 87

Answers (3)

Dan Zheng
Dan Zheng

Reputation: 1673

The line duplication happens because you are writing to the original file while also reading it.

It turns out that deleting and editing lines from a file can be quite difficult. If you want to edit lines in a file, one easy solution is to write to a new temporary file, rename it to the original file, and delete the temporary file.

Upvotes: 2

deamentiaemundi
deamentiaemundi

Reputation: 5525

You can do it it in-place, but it is dangerous, you might loose data if something fails.

A slightly simplified version would be

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

int reverse(int otherWord)
{
  if (otherWord) {
    return 0;
  } else {
    return 1;
  }
}

void capitalise(char *s)
{
  int start = 1;
  int otherWord = 1;
  for (; *s; s++) {
    if (start && otherWord) {
      *s = toupper(*s);
    }
    start = isspace(*s);
    if (start) {
      otherWord = reverse(otherWord);
    }
  }
}

int main(void)
{
  FILE *fp;
  char *line = NULL;
  size_t len = 0;
  ssize_t read;
  long offset = 0L;
  int res;
  // you might prefer "w+" instead
  fp = fopen("poem.txt", "r+");
  if (fp == NULL) {
    fprintf(stderr, "Opening file poem.txt failed\n");
    exit(EXIT_FAILURE);
  }

  while ((read = getline(&line, &len, fp)) != -1) {
    capitalise(line);
    // set position relative to start of file
    if ((res = fseek(fp, offset, SEEK_SET)) < 0) {
      fprintf(stderr, "fseek failed\n");
      exit(EXIT_FAILURE);
    }
    // printing line sets file pointer to end of line
    fprintf(fp, "%s", line);
    // get that position
    offset = ftell(fp);
  }
  // fclose() might fail, too, see man-page for details
  fclose(fp);
  if (line) {
    free(line);
  }
  exit(EXIT_SUCCESS);
}

Upvotes: 2

user7207172
user7207172

Reputation:

if I remember correctly, you should be able to rewrite the content for the file since it already exist with the flag "w". Replace your "r+" with "w"

Upvotes: 0

Related Questions