SamuelNLP
SamuelNLP

Reputation: 4136

Erase last members of line from text file

I have a text file as data.txt and I want to delete the last members of each line:

Here's the text file:

2031,2,0,0,0,0,0,0,54,0,
2027,2,0,0,0,0,0,0,209,0,
2029,2,0,0,0,0,0,0,65,0,
2036,2,0,0,0,0,0,0,165,0,

I would like to delete so it becomes:

2031,2,0,0,0,0,0,0,
2027,2,0,0,0,0,0,0,
2029,2,0,0,0,0,0,0,
2036,2,0,0,0,0,0,0,

I'm working in C but as the numbers can have two or three digits, I'm not sure how to do this.

Upvotes: 0

Views: 69

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 753990

A couple of uses of strrchr() can do the job:

#include <string.h>

void zap_last_field(char *line)
{
    char *last_comma = strrchr(line, ',');
    if (last_comma != 0)
    {
        *last_comma = '\0';
        last_comma = strrchr(line, ',');
        if (last_comma != 0)
            *(last_comma + 1) = '\0';
    }
}

Compiled code that seems to work. Note that given a string containing a single comma, it will zap that comma. If you don't want that to happen, then you have to work a little harder.

Test code for zap_last_field()

#include <string.h>

extern void zap_last_field(char *line);

void zap_last_field(char *line)
{
    char *last_comma = strrchr(line, ',');
    if (last_comma != 0)
    {
        *last_comma = '\0';
        last_comma = strrchr(line, ',');
        if (last_comma != 0)
            *(last_comma + 1) = '\0';
    }
}

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    char *line = malloc(4096);
    if (line != 0)
    {

        while (fgets(line, 4096, stdin) != 0)
        {
            printf("Line: %s", line);
            zap_last_field(line);
            printf("Zap1: %s\n", line);
        }
        free(line);
    }
    return(0);
}

This has been vetted with valgrind and is OK on both the original data file and the mangled data file listed below. The dynamic memory allocation is there to give valgrind the maximum chance of spotting any problems.

I strongly suspect that the core dump reported in a comment happens because the alternative test code tried to pass a literal string to the function, which won't work because literal strings are not generally modifiable and this code modifies the string in situ.

Test code for zap_last_n_fields()

If you want to zap the last couple of fields (a controlled number of fields), then you'll probably want to pass in a count of the number of fields to be zapped and add a loop. Note that this code uses a VLA so it requires a C99 compiler.

#include <string.h>

extern void zap_last_n_fields(char *line, size_t nfields);

void zap_last_n_fields(char *line, size_t nfields)
{
    char *zapped[nfields+1];

    for (size_t i = 0; i <= nfields; i++)
    {
        char *last_comma = strrchr(line, ',');
        if (last_comma != 0)
        {
            zapped[i] = last_comma;
            *last_comma = '\0';
        }
        else
        {
            /* Undo the damage wrought above */
            for (size_t j = 0; j < i; j++)
                *zapped[j] = ',';
            return;
        }
    }
    zapped[nfields][0] = ','; 
    zapped[nfields][1] = '\0';
}

#include <stdio.h>

int main(void)
{
    char line1[4096];

    while (fgets(line1, sizeof(line1), stdin) != 0)
    {
        printf("Line: %s", line1);
        char line2[4096];
        for (size_t i = 1; i <= 3; i++)
        {
            strcpy(line2, line1);
            zap_last_n_fields(line2, i);
            printf("Zap%zd: %s\n", i, line2);
        }
    }
    return(0);
}

Example run — using your data.txt as input:

Line: 2031,2,0,0,0,0,0,0,54,0,
Zap1: 2031,2,0,0,0,0,0,0,54,
Zap2: 2031,2,0,0,0,0,0,0,
Zap3: 2031,2,0,0,0,0,0,
Line: 2027,2,0,0,0,0,0,0,209,0,
Zap1: 2027,2,0,0,0,0,0,0,209,
Zap2: 2027,2,0,0,0,0,0,0,
Zap3: 2027,2,0,0,0,0,0,
Line: 2029,2,0,0,0,0,0,0,65,0,
Zap1: 2029,2,0,0,0,0,0,0,65,
Zap2: 2029,2,0,0,0,0,0,0,
Zap3: 2029,2,0,0,0,0,0,
Line: 2036,2,0,0,0,0,0,0,165,0,
Zap1: 2036,2,0,0,0,0,0,0,165,
Zap2: 2036,2,0,0,0,0,0,0,
Zap3: 2036,2,0,0,0,0,0,

It also correctly handles a file such as:

2031,0,0,
2031,0,
2031,
2031
,

Upvotes: 2

Related Questions