Loop to Remove Excessive Whitespace From a Char Array (C++)

Viewed 132

I am trying to create a simple loop to read in an array of characters and print back the array without any excessive white-space.

I am having issues with my loop and was hoping to get some assistance.

for(int i=0;i<ARR_SIZE;++i) //Initialize loop
{
if(isspace(arr[i])&&isspace(arr[i+1]) //If check for double whitespace
   {arr[i+1] = arr[i+2];} //If detected, move the character after the whitespace (+2) to (+1)
 }

This does remove the double white space, but I'm having trouble with the logic as to what I'd do to copy all the other characters in.

I.e. current if I put in "t__est" I'd get "t_eest".

Its a fairly simple question, but I think I'm either thinking too much about it, or missing some simple logical step.

Any advice would be appreciated.

3 Answers

In brief, you should not only move the next character to replace duplicated space, but move all characters afterwards.

The simplest way is of course to define another array, as mentioned in another answer.

However, as you are just removing characters, this could be done easily in-place:

Just keep two pointers, one for reading the character, one for the position to write. The "read" pointer will iterate from string start to end

in pseudo-code, and assume you are dealing with C-Style string (i.e. null-terminated char array):

char* src = inputString;
char* dest = src;
while src != NULL {
    if *src is not space OR previous char is not space { 
        write to dest pos, and increment dest
    }
    increment src
}
*dest = NULL;  // null-terminating at new position

in shorter form (which I tried not to sacrifice readability too much):

char* src = dest = inputString;
for ( ; *src; ++src) {
    if (src == inputString || ! isspace(*src) || *src != *(src-1)) {
        *(dest++) = *src;
    }
}
*dest = '\0';

you can define another array to store in the result. then, go through the input chars, adding each char to the result array only when this char is not space or the previous is not.

char output[ARR_SIZE];
int insertloc=0;

for(int i=0;i<ARR_SIZE;++i) //Initialize loop
{
   if(i==0||!isspace(arr[i])||isspace(arr[i-1]) //If check for double whitespace
       output[insertloc++]=arr[i];
}

this can be also done in_place like this (without defining another array) but the concept is similar to the above.

int insertloc=0;

for(int i=0;i<ARR_SIZE;++i) //Initialize loop
{
   if(i==0||!isspace(arr[i])||isspace(arr[i-1]) //If check for double whitespace
       arr[insertloc++]=arr[i];
}

This is a case where using the STL algorithms allows you to have the easiest solution (little code and hard to get wrong)

In this case, std::remove_if is what you want. You send a range and a predicate, and it will move the elements you don't need at the end but still preserves the order.

You can do it with lambda to store the state of the previous value:

#include <algorithm>
#include <cctype>

void filterspace(char* str, std::size_t len){
    std::remove_if(str,str+len,
        [prev=false](auto x) mutable
        { 
            if(prev&&isspace(x))
                return true;
            prev=isspace(x);
            return false;
        }
    );
}

You can check a demo with execution on Godbolt here

If you want, you can also use the return of std::remove_if to get the length of the new string.

Related