Tag Archives: Trim

Trim a string in C

Left trim

To left trim a string, find the length of prefix containing the characters to trim with strspn(), and then move the rest of the string forwards on top of it with memmove(), not forgetting to move the terminating nul character. Note that checking for the prefix being greater than zero will cover the case where the string is empty.

char *ltrim(char *str, const char *seps)
{
    size_t totrim;
    if (seps == NULL) {
        seps = "\t\n\v\f\r ";
    }
    totrim = strspn(str, seps);
    if (totrim > 0) {
        size_t len = strlen(str);
        if (totrim == len) {
            str[0] = '\0';
        }
        else {
            memmove(str, str + totrim, len + 1 - totrim);
        }
    }
    return str;
}

Right trim

To right trim, scan the string from the right and replace any characters to trim with nul characters, until you find a character you want to keep or you run out of string.

char *rtrim(char *str, const char *seps)
{
    int i;
    if (seps == NULL) {
        seps = "\t\n\v\f\r ";
    }
    i = strlen(str) - 1;
    while (i >= 0 && strchr(seps, str[i]) != NULL) {
        str[i] = '\0';
        i--;
    }
    return str;
}

Trim

To trim both ends of a string, just right trim it and then left trim it, or vice-versa.

char *trim(char *str, const char *seps)
{
    return ltrim(rtrim(str, seps), seps);
}

Test program

This tries all of the important cases with a space as the separator.

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

#include <trim.h>

size_t maxlen(char **strings, size_t len)
{
    unsigned int i;
    size_t max = 0;
    for (i = 0; i < len; i++) {
        if (strlen(strings[i]) > max) {
            max = strlen(strings[i]);
        }
    }
    return max;
}

int main(void)
{
    char *strings[] = {"", " ", "  " "test", " test", "test ", " test ",
        "  test", "test  ", "  test  "};
    const size_t n = sizeof(strings) / sizeof(char *);
    unsigned int i;
    char *str = malloc(maxlen(strings, n) + 1);
    for (i = 0; i < n; i++) {
        strcpy(str, strings[i]);
        trim(str, NULL);
        printf("%s\n", str);
    }
    free(str);
    return 0;
}

How to trim a std::string in C++

There is no standard way of trimming a string, but it’s possible to implement using the methods in the string class:

  • Left trim: Use find_first_not_of() to find the characters to erase
  • Right trim: Use find_first_of() to find the characters to erase
  • Trim: Do a right trim followed by a left trim (or vice-versa)

Use erase() to actually erase the characters.

Here is my implementation. It defaults to trimming whitespace characters but you can specify any string of characters as the second argument.

std::string& ltrim(std::string& str, const std::string& chars = "\t\n\v\f\r ")
{
    str.erase(0, str.find_first_not_of(chars));
    return str;
}

std::string& rtrim(std::string& str, const std::string& chars = "\t\n\v\f\r ")
{
    str.erase(str.find_last_not_of(chars) + 1);
    return str;
}

std::string& trim(std::string& str, const std::string& chars = "\t\n\v\f\r ")
{
    return ltrim(rtrim(str, chars), chars);
}

Here’s a test program:

int main()
{
    std::string strings[] = {"", " ", "test", " test", "test ", " test "};
    const size_t n = sizeof(strings) / sizeof(std::string);
    for (unsigned int i = 0; i < n; ++i) {
        std::string str = strings[i];
        trim(str);
        std::cout << "\"" << str << "\"" << "\n";
    }
}

And here’s the valgrind output:

==23049== Memcheck, a memory error detector
==23049== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==23049== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==23049== Command: ./trim
==23049==
""
""
"test"
"test"
"test"
"test"
==23049==
==23049== HEAP SUMMARY:
==23049==     in use at exit: 0 bytes in 0 blocks
==23049==   total heap usage: 16 allocs, 16 frees, 475 bytes allocated
==23049==
==23049== All heap blocks were freed -- no leaks are possible
==23049==
==23049== For counts of detected and suppressed errors, rerun with: -v
==23049== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Related