Paul
Paul

Reputation: 275

C++ Implementation to Trim Char Array of Leading/Trailing White Space Not Working As Expected

I am trying to implement a simple and safe way to trim a char array of both leading and trailing white space. It works to remove the leading white space, but isn't working for the other side. Can anyone see what I am doing wrong? Here is my code:

template<size_t charCount>
void strtrim_safe( char (&output)[charCount] ) {
  char *ptr = output;
  size_t n = charCount;
  size_t start = 0;
  size_t end = 0;

  // Find the start and end position of trimmed string
  while ( n-- != 0 && *ptr != 0 ) {
    if ( *ptr == 32 ) {
        if ( end == 0 ) {
            start++;
        } else {
            break;
         }
    } else {
        end++;
    }

    ptr++;
  }

  // Shift the char array 
  for ( int i = start, j =  0; i < end, j < charCount; i++, j++ ) {
      output[j] = output[i];
  }
}

Thanks in advance!

EDIT1: Thanks to your input, I think I have fixed the issue. The following code in place of the code under Shift the char array seems to do the trick:

// Shift the char array 
for ( int i = start, j =  0; i < end + start && j < charCount; i++, j++ ) {
    output[j] = output[i];
}
output[end] = 0;

Tested with trailing white space only, leading white space only, white space on both sides, and of course, no white space. So far, so good

EDIT2: In order to account for possible interior spaces, I did the checking within the while loop and came up with this:

template<size_t charCount>
void strtrim_safe( char (&output)[charCount] ) {
   char *ptr = output;
   size_t n = charCount;
   size_t start = 0;
   size_t end = 0;

   // Find the start and end position of trimmed string
   while ( n-- != 0 && *ptr != 0 ) {
      if ( *ptr == 32 ) {
        if ( end == 0 ) {
            start++;
        } else {
          size_t endTmp = end;
          while ( *ptr == 32 && n-- != 0 && *ptr != 0 ) {
            end++;
            ptr++;
          }
        if ( *ptr == 0 || n == 0 ) {
          end = endTmp;
        } else {
          end++;
        }
      }
    } else {
      end++;
    }

    ptr++;
  }

  // Shift the char array 
  for ( int i = start, j =  0; j < end + start && j < charCount; i++, j++ ) {
    output[j] = output[i];
  }
  output[end] = 0;
}

Upvotes: 0

Views: 16326

Answers (4)

Twareintor
Twareintor

Reputation: 41

a more simple version of a function to trim leading and trailing spaces:

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

void trim(char** arg, char c)
{
    char* p = *arg; // preserve the original string
    while(*p++); p--; while(c==*--p) *p = 0; // deleting trailing spaces
    while(c==*(*arg)++); (*arg)--; // ignoring leading spaces
}

int main()
{
    char* pszX[] = {
     "             THE QUICK brown fox 012        ",
       "           THE QUICK brown fox 012",
                  "THE QUICK brown fox 012               ",        
                 " THE QUICK brown fox 012 ",
                 " THE QUICK brown fox 012",    
                  "THE QUICK brown fox 012 ",        
                  "THE QUICK brown fox 012",                
                    };
    int i;
    for(i = 0; i<7; i++)
    {
        char* arg = strdup(pszX[i]);
        trim(&arg, ' ');
        printf("\"%s\"\n", arg);
    }
    return 0;
}

It can be adapted, to trim only leading or only trailing spaces too.

Upvotes: 1

Twareintor
Twareintor

Reputation: 41

I have designed three functions for trimming the spaces of a char* array, at left, at right and at both ends, by returning a pointer to the new processed string.

char* LTrim(char* szX)
{
    if(' '==szX[0]) while(' '==(++szX)[0]);
    return szX;
}

char* RTrim(char* szX)
{
    int i = strlen(szX);
    while(' '==szX[--i]) szX[i] = 0;
    return szX;
}

char* Trim(char* szX)
{
    szX = LTrim(szX);
    szX = RTrim(szX);
    return szX;
}

An example of their usage and implementation is here

Of course, they aren't working with const char* but are very useful especially for processing fixed-width text tables.

Upvotes: 0

JustKevin
JustKevin

Reputation: 374

I think you're problem is that you don't know if the first space at the end of the string is a trailing space or not, so you have to calculate the position of the null termination byte and double back from there to get end.

What if you have an interior space as in " hello there. "?

I think that your algorithm is wrong. If you want to calculate start and the null-termination byte on a single while loop that's fine, the code looks like this:

I see your point about adding start to end, but it missed the interior space clause.

size_t i = 0;
bool flag_leadingspace = TRUE; // effectively TRUE
while( *ptr != 0 )
{

    if( *ptr == 32 ) // space
    {
        if( flag_leadingspace ) start ++; // got it.
    }
    else // ---> *ptr != 32 // non-space
    {
        flag_leadingspace = FALSE; // effectively FALSE
    }
    ptr++; i++;
}

ptr--;         // since *ptr === 0
charCount = i; // you're character count 
end = i-1;     // we start looking for the end at i-1;

while( *ptr == 32 )
{ // if there is no trailing space, then end is already set
  //   and the block is skipped.

    end --;
    ptr --;
}

// Shift the char array // from above 
for ( int i = start, j =  0; i < end; i++, j++ )
{
    output[j] = output[i];
}

// and corrected to null terminate.
output[j] = 0;

well almost a copy paste, but you get the point. I hope that works for the function.

Upvotes: 1

jmucchiello
jmucchiello

Reputation: 18984

void strtrim(char* str) {
    int start = 0; // number of leading spaces
    char* buffer = str;
    while (*str && *str++ == ' ') ++start;
    while (*str++); // move to end of string
    int end = str - buffer - 1; 
    while (end > 0 && buffer[end - 1] == ' ') --end; // backup over trailing spaces
    buffer[end] = 0; // remove trailing spaces
    if (end <= start || start == 0) return; // exit if no leading spaces or string is now empty
    str = buffer + start;
    while ((*buffer++ = *str++));  // remove leading spaces: K&R
}

Upvotes: 8

Related Questions