Как стандартным способом обрезать начальные / конечные пробелы? - PullRequest
162 голосов
/ 23 сентября 2008

Существует ли чистый, желательно стандартный метод обрезания начальных и конечных пробелов из строки в C? Я бы бросил свой, но я бы подумал, что это общая проблема с таким же распространенным решением.

Ответы [ 37 ]

0 голосов
/ 01 февраля 2018

Здесь я использую динамическое выделение памяти для обрезки входной строки до функции trimStr. Сначала мы выясним, сколько непустых символов существует во входной строке. Затем мы выделяем массив символов с таким размером и заботимся о нулевом символе в конце. Когда мы используем эту функцию, нам нужно освободить память внутри основной функции.

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

char *trimStr(char *str){
char *tmp = str;
printf("input string %s\n",str);
int nc = 0;

while(*tmp!='\0'){
  if (*tmp != ' '){
  nc++;
 }
 tmp++;
}
printf("total nonempty characters are %d\n",nc);
char *trim = NULL;

trim = malloc(sizeof(char)*(nc+1));
if (trim == NULL) return NULL;
tmp = str;
int ne = 0;

while(*tmp!='\0'){
  if (*tmp != ' '){
     trim[ne] = *tmp;
   ne++;
 }
 tmp++;
}
trim[nc] = '\0';

printf("trimmed string is %s\n",trim);

return trim; 
 }


int main(void){

char str[] = " s ta ck ove r fl o w  ";

char *trim = trimStr(str);

if (trim != NULL )free(trim);

return 0;
}
0 голосов
/ 09 марта 2016
void trim(char* string) {
    int lenght = strlen(string);
    int i=0;

    while(string[0] ==' ') {
        for(i=0; i<lenght; i++) {
            string[i] = string[i+1];
        }
        lenght--;
    }


    for(i=lenght-1; i>0; i--) {
        if(string[i] == ' ') {
            string[i] = '\0';
        } else {
            break;
        }
    }
}
0 голосов
/ 22 мая 2013

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

#include <string.h>

void rstrip(char *string)
{
  int l;
  if (!string)
    return;
  l = strlen(string) - 1;
  while (isspace(string[l]) && l >= 0)
    string[l--] = 0;
}

void lstrip(char *string)
{
  int i, l;
  if (!string)
    return;
  l = strlen(string);
  while (isspace(string[(i = 0)]))
    while(i++ < l)
      string[i-1] = string[i];
}

void strip(char *string)
{
  lstrip(string);
  rstrip(string);
}
0 голосов
/ 23 сентября 2008

Вот функция, чтобы делать то, что вы хотите. Следует позаботиться о вырожденных случаях, когда вся строка является пробелом. Вы должны передать в выходной буфер и длину буфера, что означает, что вы должны передать в выделенный вами буфер.

void str_trim(char *output, const char *text, int32 max_len)
{
    int32 i, j, length;
    length = strlen(text);

    if (max_len < 0) {
        max_len = length + 1;
    }

    for (i=0; i<length; i++) {
        if ( (text[i] != ' ') && (text[i] != '\t') && (text[i] != '\n') && (text[i] != '\r')) {
            break;
        }
    }

    if (i == length) {
        // handle lines that are all whitespace
        output[0] = 0;
        return;
    }

    for (j=length-1; j>=0; j--) {
        if ( (text[j] != ' ') && (text[j] != '\t') && (text[j] != '\n') && (text[j] != '\r')) {
            break;
        }
    }

    length = j + 1 - i;
    strncpy(output, text + i, length);
    output[length] = 0;
}

Операторы if в циклах, вероятно, можно заменить на isspace (text [i]) или isspace (text [j]) , чтобы сделать строки немного легче для чтения , Я думаю, что я установил их таким образом, потому что были некоторые символы, которые я не хотел проверять, но похоже, что я сейчас покрываю все пробелы: -)

0 голосов
/ 16 марта 2010

Немного опоздал к игре, но я брошу свои рутины в драку. Они, вероятно, не самые эффективные, но я считаю, что они правильные и простые (с rtrim() расширением сложности):

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

/*
    Public domain implementations of in-place string trim functions

    Michael Burr
    michael.burr@nth-element.com
    2010
*/

char* ltrim(char* s) 
{
    char* newstart = s;

    while (isspace( *newstart)) {
        ++newstart;
    }

    // newstart points to first non-whitespace char (which might be '\0')
    memmove( s, newstart, strlen( newstart) + 1); // don't forget to move the '\0' terminator

    return s;
}


char* rtrim( char* s)
{
    char* end = s + strlen( s);

    // find the last non-whitespace character
    while ((end != s) && isspace( *(end-1))) {
            --end;
    }

    // at this point either (end == s) and s is either empty or all whitespace
    //      so it needs to be made empty, or
    //      end points just past the last non-whitespace character (it might point
    //      at the '\0' terminator, in which case there's no problem writing
    //      another there).    
    *end = '\0';

    return s;
}

char*  trim( char* s)
{
    return rtrim( ltrim( s));
}
0 голосов
/ 06 мая 2011

Большинство ответов до сих пор делают одно из следующего:

  1. Возврат в конце строки (то есть найти конец строки и затем искать назад, пока не будет найден непробельный символ), или
  2. Сначала позвоните strlen(), сделав второй проход через всю строку.

Эта версия делает только один проход и не возвращается. Следовательно, он может работать лучше, чем другие, хотя только в том случае, если распространены сотни пробелов (что весьма обычно при работе с выводом запроса SQL).

static char const WHITESPACE[] = " \t\n\r";

static void get_trim_bounds(char  const *s,
                            char const **firstWord,
                            char const **trailingSpace)
{
    char const *lastWord;
    *firstWord = lastWord = s + strspn(s, WHITESPACE);
    do
    {
        *trailingSpace = lastWord + strcspn(lastWord, WHITESPACE);
        lastWord = *trailingSpace + strspn(*trailingSpace, WHITESPACE);
    }
    while (*lastWord != '\0');
}

char *copy_trim(char const *s)
{
    char const *firstWord, *trailingSpace;
    char *result;
    size_t newLength;

    get_trim_bounds(s, &firstWord, &trailingSpace);
    newLength = trailingSpace - firstWord;

    result = malloc(newLength + 1);
    memcpy(result, firstWord, newLength);
    result[newLength] = '\0';
    return result;
}

void inplace_trim(char *s)
{
    char const *firstWord, *trailingSpace;
    size_t newLength;

    get_trim_bounds(s, &firstWord, &trailingSpace);
    newLength = trailingSpace - firstWord;

    memmove(s, firstWord, newLength);
    s[newLength] = '\0';
}
0 голосов
/ 26 сентября 2014

Вот что я раскрыл относительно вопроса в коде ядра Linux:

/**
 * skip_spaces - Removes leading whitespace from @s.
 * @s: The string to be stripped.
 *
 * Returns a pointer to the first non-whitespace character in @s.
 */
char *skip_spaces(const char *str)
{
    while (isspace(*str))
            ++str;
    return (char *)str;
}

/**
 * strim - Removes leading and trailing whitespace from @s.
 * @s: The string to be stripped.
 *
 * Note that the first trailing whitespace is replaced with a %NUL-terminator
 * in the given string @s. Returns a pointer to the first non-whitespace
 * character in @s.
 */
char *strim(char *s)
{
    size_t size;
    char *end;

    size = strlen(s);

    if (!size)
            return s;

    end = s + size - 1;
    while (end >= s && isspace(*end))
            end--;
    *(end + 1) = '\0';

    return skip_spaces(s);
}

Предполагается, что он не содержит ошибок из-за происхождения; -)

Мой кусок ближе к принципу KISS, я думаю:

/**
 * trim spaces
 **/
char * trim_inplace(char * s, int len)
{
    // trim leading
    while (len && isspace(s[0]))
    {
        s++; len--;
    }

    // trim trailing
    while (len && isspace(s[len - 1]))
    {
        s[len - 1] = 0; len--;
    }

    return s;
}
0 голосов
/ 18 июля 2012
#include<stdio.h>
#include<ctype.h>

main()
{
    char sent[10]={' ',' ',' ','s','t','a','r','s',' ',' '};
    int i,j=0;
    char rec[10];

    for(i=0;i<=10;i++)
    {
        if(!isspace(sent[i]))
        {

            rec[j]=sent[i];
            j++;
        }
    }

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

}
0 голосов
/ 23 сентября 2008

Лично я бы накатил свой. Вы можете использовать strtok, но вам нужно позаботиться об этом (особенно если вы удаляете главные символы), чтобы вы знали, что такое память.

Избавиться от конечных пробелов легко и довольно безопасно, так как вы можете просто поставить 0 поверх последнего пробела, считая от конца до конца. Избавление от пробелов означает движение вокруг. Если вы хотите сделать это на месте (возможно, разумно), вы можете просто перемещать все назад на один символ, пока не будет пробела. Или, чтобы быть более эффективным, вы можете найти индекс первого непробельного символа и сдвинуть все обратно на это число. Или вы можете просто использовать указатель на первый непробельный символ (но тогда вы должны быть осторожны так же, как и в случае с strtok).

0 голосов
/ 23 сентября 2008

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

void inplace_trim(char* s)
{
    int start, end = strlen(s);
    for (start = 0; isspace(s[start]); ++start) {}
    if (s[start]) {
        while (end > 0 && isspace(s[end-1]))
            --end;
        memmove(s, &s[start], end - start);
    }
    s[end - start] = '\0';
}

char* copy_trim(const char* s)
{
    int start, end;
    for (start = 0; isspace(s[start]); ++start) {}
    for (end = strlen(s); end > 0 && isspace(s[end-1]); --end) {}
    return strndup(s + start, end - start);
}

strndup() является расширением GNU. Если у вас его нет или что-то в этом роде, сверните свое. Например:

r = strdup(s + start);
r[end-start] = '\0';
...