Удаление пробела до первого допустимого символа C

В основном я хочу удалить все начальные пробелы перед первым допустимым символом в массиве.

Например, если у меня есть что-то вроде ' 1.6, 1.7', я хочу, чтобы это было '1.6, 1.7', или если бы это было просто '1.7, 1.8', то было бы '1.7, 1.8'

Это мой метод для пробелов, однако он показывает только, где находятся пробелы. Мне нужна помощь в его удалении.

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
        }
     }
   }
}

person Sam Thers    schedule 11.12.2014    source источник
comment
В основном зацикливайте и подсчитывайте количество ведущих пробелов, а затем сдвигайте весь массив влево на это значение.   -  person Gillespie    schedule 12.12.2014
comment
Student::removeSpace() больше похож на C++, чем на C. Каково определение storeArray?   -  person Christophe    schedule 12.12.2014
comment
Возможный дубликат Как мне обрезать начало/конец пробел стандартным способом?   -  person kamino    schedule 12.12.2014
comment
Кстати. вы удаляете только пробелы, за которыми следуют не промежутки времени. 'xx' приведет к 'xx', а не к 'xx'.   -  person Christophe    schedule 12.12.2014
comment
Остерегайтесь (отсутствие) побочных эффектов i в (isspace(storeArray[i]) && !(isspace(storeArray[i++]))   -  person pmg    schedule 12.12.2014
comment
@RPGillespie, как зациклиться, если после главного символа есть пробелы?   -  person Sam Thers    schedule 12.12.2014
comment
Вы имеете в виду вот так?: while(isspace(*source++));while((*dest++=*source++)); Полезно изучать указатели.   -  person technosaurus    schedule 12.12.2014


Ответы (4)


Чтобы удалить лишние пробелы, пройдитесь по строке:

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);
  }
}
person chux - Reinstate Monica    schedule 11.12.2014
comment
Мне это нравится. Если строки являются реальными строками, единственное, что я бы сделал по-другому, это чтобы функция удаления вычисляла длину и избавлялась от необходимости отправлять размер. - person David C. Rankin; 12.12.2014
comment
@David C. Rankin Согласен, но OP, похоже, хочет работать с массивом char, а не со строкой C. Сообщение IAC OP выглядит как C ++, но с тегом C. - person chux - Reinstate Monica; 12.12.2014

Попробуйте что-то вроде этого:

#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;
}
person Gillespie    schedule 11.12.2014
comment
Спасибо, но разве конечный результат не будет Checkitout.? Потому что вы удаляете все пробелы - person Sam Thers; 12.12.2014
comment
Нет, собери сам и посмотри. Этот код удаляет только начальные пробелы. Код breaks после обнаружения первого непробельного символа. - person Gillespie; 12.12.2014

Если вы уверены, что c-строки не длиннее MAX_SIZE и являются строками с нулевым завершением:

   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
   } 

Если вы работаете на С++ (как предлагает Student::removeSpace()) и если вы действительно не хотите работать с std::string, вы можете заменить все это на:

   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]); 

Правка. Если вы хотите избежать перемещения строк и можете позволить себе изменить указатели строк (т. е. вы не выделяли строки динамически), вы можете сделать так же:

   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
person Christophe    schedule 11.12.2014
comment
Спасибо, мне нравится использовать c-строки, и они не будут длиннее MAX_SIZE. Дело в том, как удалить конечный пробел без копирования в массив? - person Sam Thers; 12.12.2014
comment
Прокрутите массив в обратном порядке и установите последний пробел, с которым вы столкнулись, равным '\0' - person Gillespie; 12.12.2014
comment
@RPGillespie, извини, я не с тобой. Почему вы установили последний пробел на '\0'? Я пытаюсь удалить только ведущие пробелы - person Sam Thers; 12.12.2014
comment
вы должны использовать memmove вместо strcpy. - person BLUEPIXY; 12.12.2014
comment
@BLUEPIXY Да, это достойная альтернатива! Тогда вам не нужно беспокоиться о нулевом терминаторе. - person Christophe; 12.12.2014
comment
@SamThers Вы спросили, как удалить конечный пробел, и вы делаете это, перебирая строку в обратном порядке, и после встречи с первым символом, не являющимся пробелом, вы устанавливаете предыдущий пробел в '\0', тем самым завершая строку, таким образом удаляя конечный пробел. - person Gillespie; 12.12.2014
comment
@SamThers на самом деле strcpy() или memmove() сдвигают символы в начало строки в том же массиве. Там нет пути вокруг. Альтернативой является изменение указателя. Однако проблема заключается в том, что вы теряете след своего исходного указателя, и если строка была выделена динамически, у вас будет, если у вас не будет возможности освободить ее позже. - person Christophe; 12.12.2014
comment
strcpy может работать, а может и не работать должным образом, если область памяти перекрывается. - person BLUEPIXY; 12.12.2014

Вы можете оставить strtrimws как отдельную функцию или включить ее содержимое в свою функцию Students::removeSpace. Следующая функция может использоваться как с назначением возврата, так и без него. Примеры: strtrimws (somestring); или char *newstring = strtrimws (somestring); Также обратите внимание, что хотя исходная строка 's' изменяется функцией, начальный адрес для 's' остается неизменным, что делает его безопасным для использования с динамически размещаемыми строками. Ниже показано в контексте с вашей функцией removeSpace:

#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]);
}

ПРИМЕЧАНИЕ. если вы инициализировали все указатели на zero/NULL в storeArray перед назначением строк (некоторым или всем) из pointers-to-char, вы можете упростить/улучшить removeSpace, удалив жестко заданное число итераций для i и заменив его на просто:

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

Пример использования функции:

#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;
}

вывод:

$ ./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'
person David C. Rankin    schedule 12.12.2014