2

I basically have want to remove all the leading whitespace before the first valid character in an array.

For example if I have something like ' 1.6, 1.7', I want it to be '1.6, 1.7' or if it was just '1.7, 1.8', then it would be '1.7, 1.8'

This is my method for the whitespace, however it only shows where the whitespace are. I need help removing it.

char **storeArray

void Students::removeSpace()
{
   int MAX_SIZE = 30;
   for(int i=0; i<3; i++)
   {
     for(int j=0; j<MAX_SIZE; j++)
     {
        if(isspace(storeArray[i][j]) && !(isspace(storeArray[i][j++])
        {
          // I NEED HELP HERE. I'M TRYING TO REMOVE ALL THE LEADING WHITESPACE ONLY
        }
     }
   }
}
BLUEPIXY
  • 39,699
  • 7
  • 33
  • 70
Sam Thers
  • 67
  • 3
  • 12
  • 1
    Basically loop and count how many leading spaces there are, and then shift the whole array left by that value. – Gillespie Dec 11 '14 at 22:47
  • 4
    Students::removeSpace() looks more like C++ than C. What's the definition of storeArray ? – Christophe Dec 11 '14 at 22:47
  • Possible duplicate of [How do I trim leading/trailing whitespace in a standard way?](http://stackoverflow.com/questions/122616/how-do-i-trim-leading-trailing-whitespace-in-a-standard-way) – kamino Dec 11 '14 at 22:49
  • Btw. you only remove whitespaces that are followed by non whilespaces. ' xx' would result in ' xx' and not 'xx'. – Christophe Dec 11 '14 at 22:49
  • Beware of (absence of) side effects to `i` in `(isspace(storeArray[i]) && !(isspace(storeArray[i++]))` – pmg Dec 11 '14 at 22:51
  • @RPGillespie, how do I loop if there are whitespace after the leading character? – Sam Thers Dec 11 '14 at 22:55
  • You mean like this?: `while(isspace(*source++));while((*dest++=*source++));` It's helpful to learn pointers. – technosaurus Dec 12 '14 at 04:08

4 Answers4

2

To remove extra white-space, march through the string:

void Remove_Leading_ExtraMiddle_Trailing_Whitespace(char *s, int size) {
  char *end = &s[size];
  char *t = s;
  // skip leading
  while (isspace(*s))
    s++;

  // middle
  for (;;) {
    while (!isspace(*s) && *s != '\0') {
      *t++ = *s++;
    }
    if (*s == '\0')
      break;
    *t = *s++;
    while (isspace(*s))
      s++;
    if (*s == '\0') {
      break;
    }
    t++;
  }

  // end
  while (t < end) {
    *t++ = '\0';
  }
}

void removeSpace() {
  int MAX_SIZE = 30;
  char storeArray[4][MAX_SIZE];
  for (int i = 0; i < 3; i++) {
    Remove_Leading_ExtraMiddle_Trailing_Whitespace(storeArray[i], MAX_SIZE);
  }
}
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • I like it. If the strings are actual strings, only thing I'd do different is have the remove function calculate the length and dispense with the need to send the size. – David C. Rankin Dec 11 '14 at 23:57
  • 1
    @David C. Rankin Agree, but OP seems to want to work with array of `char` rather than C string. IAC OP's post looks C++ like yet with C tag. – chux - Reinstate Monica Dec 11 '14 at 23:58
1

Try something like this:

#include <stdio.h>

int main()
{
    char storeArray[20] = "   Check it out.";
    int whitespace = 0;

    printf("%s\n", storeArray);

    //Count leading whitespace
    for(int i=0; i<20; i++)
    {
        if(storeArray[i] == ' ' || storeArray[i] == '\t')
            whitespace++;
        else
            break;
    }

    //Shift everything left
    for(int i=0; i<20; i++)
    {
        if (i+whitespace < 20)
            storeArray[i] = storeArray[i+whitespace];
        else
            storeArray[i] = 0;
    }

    printf("%s\n", storeArray);

    return 0;
}
Gillespie
  • 5,780
  • 3
  • 32
  • 54
  • Thanks, but wouldn't the end result be `Checkitout.`? Because you are removing all whitespace – Sam Thers Dec 11 '14 at 23:20
  • Nope, compile it yourself and see. This code only gets rid of the leading whitespace. The code `break`s after encountering the first non-whitespace character. – Gillespie Dec 11 '14 at 23:51
0

If you're sure that the c-strings are not longer than MAX_SIZE and if they are null terminated strings:

   for(int i=0; i<3; i++)
   {
     int j=0; 
     while (j<MAX_SIZE && isspace(storeArray[i][j]) 
         j++;
     if (j==MAX_SIZE)  // oops ! Not null terminated and only whitespace ? 
         storeArray[i][0]='\0';
     else if (j>0) // if no leading whiespace do nothing !
         strcpy (storeArray[i], &storeArray[i][j]);    // if you like c style
   } 

If you are working in C++ (as the Student::removeSpace() suggest), and if you really don't want to work with std::string, then you could consider replace all this with:

   for(int i=0; i<3; i++)
       copy(find_if(storeArray[i], storeArray[i] + MAX_SIZE, [](char c){ return c && !isspace(c); }), storeArray[i] + MAX_SIZE, storeArray[i]); 

Edit: If you want to avoid moving your strings, and if you can afford to change the string pointers (i.e.you didn't dynamically allocate the strings), then you could do as well:

   for(int i=0; i<3; i++)
       for (int j=MAX_SIZE-1; j>=0 && isspace(*storeArray[i]); j--) 
           storeArray[i]++;  // no move or copy, but original pointer lost forever
Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Thanks, I like using c-strings and it will not be longer than `MAX_SIZE`. Thing is, how do I remove the trailing whitespace, without copying into array? – Sam Thers Dec 11 '14 at 23:05
  • 1
    Loop through the array backwards and set the last whitespace you encounter to `'\0'` – Gillespie Dec 11 '14 at 23:07
  • @RPGillespie, Sorry I am not with you. Why would you set the last whitespace to `'\0'`? I'm trying to remove leading whitespace only – Sam Thers Dec 11 '14 at 23:18
  • you should use the `memmove` instead of `strcpy`. – BLUEPIXY Dec 11 '14 at 23:43
  • @BLUEPIXY Yes, that's a valid alternative ! You then don't have to worry about null terminator. – Christophe Dec 11 '14 at 23:49
  • @SamThers You asked how to remove the "trailing whitespace" - and you do so by looping through the string backwards and after encountering the first non-whitespace character, you set the previous whitespace to `'\0'`, thus terminating the string, thus removing the trailing whitespace. – Gillespie Dec 11 '14 at 23:53
  • @SamThers in fact strcpy() or memmove() shift the chars to the begin of the string in the same array. There's no way arround. An alternative is to modify the pointer. The problem is however that you loose the trace of your original pointer and if the string was allocated dynamically, you'll have if you have no way to free it later. – Christophe Dec 11 '14 at 23:54
  • `strcpy` may work and may not work to operate properly if the memory area is overlapping. – BLUEPIXY Dec 12 '14 at 00:05
0

You can either keep strtrimws as a separate function or incorporate its contents within your Students::removeSpace function. The following function can be used with or without assigning the return. Examples: strtrimws (somestring); or char *newstring = strtrimws (somestring); Also note, while the original string 's' is modified by the function, the start address for 's' is unchanged making it safe for use with dynamically allocated strings. Shown below in context with your removeSpace function:

#include <ctype.h>

/** remove leading and trailing whitespace, original not preserved.
 *  this funciton can be used with or without assigning the return.
 */
char *strtrimws (char *s)
{
    char *sp = s;                   /* start pointer to return  */
    char *p = s;                    /* pointer to parse string  */

    while (isspace (*s))  s++;      /* skip leading whitespace  */
    while (*s) *p++ = *s++;         /* reindex s to end         */
    while (isspace (*p)) *p-- = 0;  /* null-terminate from end  */

    return sp;
}

char **storeArray;

void Students::removeSpace()
{
    int i = 0;
    for(int i=0; i<3; i++)
        strtrimws (storeArray[i]);
}

NOTE: if you have initialized all pointers to zero/NULL in storeArray before assigning strings to (some or all) of the pointers-to-char you can simplify/improve removeSpace by eliminating the hardcoded number of iterations for i and replacing it with a simple:

void Students::removeSpace()
{
    int i = 0;
    while (storeArray[i])
        strtrimws (storeArray[i++]);
}

Example of funciton in use:

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

/** remove leading and trailing whitespace, original not preserved.
*  this funciton can be used with or without assigning return.
*/
char *strtrimws (char *s)
{
    char *sp = s;                   /* start pointer to return  */
    char *p = s;                    /* pointer to parse string  */

    while (isspace (*s))  s++;      /* skip leading whitespace  */
    while (*s) *p++ = *s++;         /* reindex s to end         */
    while (isspace (*p)) *p-- = 0;  /* null-terminate from end  */

    return sp;
}

int main (int argc, char **argv)
{
    if (argc < 2) {
        fprintf (stderr, "\n error: insufficient input. Usage:  %s char* char* ... (max 5)\n\n", argv[0]);
        return 1;
    }

    char array[5][50] = {{0}};
    int i = 0;

    for (i = 1; i < argc; i++)
    {
        strncpy (array[i-1], argv[i], strlen (argv[i]));
        printf ("\n array[%d] '%s'\n", i, strtrimws (array[i-1]));
    }

    return 0;
}

output:

$ ./bin/stripwsarray " string 1 ws " "  string 2 ws  " "   string 3 ws   "

 array[0] 'string 1 ws'

 array[1] 'string 2 ws'

 array[2] 'string 3 ws'
David C. Rankin
  • 81,885
  • 6
  • 58
  • 85