Pergunta

Existe um método limpo, de preferência padrão de aparar líder e espaços em branco a partir de uma cadeia em C? Eu fazer a minha própria, mas eu acho que este é um problema comum com uma solução igualmente comum.

Foi útil?

Solução

Se você pode modificar a seqüência:

// Note: This function returns a pointer to a substring of the original string.
// If the given string was allocated dynamically, the caller must not overwrite
// that pointer with the returned value, since the original pointer must be
// deallocated using the same allocator with which it was allocated.  The return
// value must NOT be deallocated using free() etc.
char *trimwhitespace(char *str)
{
  char *end;

  // Trim leading space
  while(isspace((unsigned char)*str)) str++;

  if(*str == 0)  // All spaces?
    return str;

  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace((unsigned char)*end)) end--;

  // Write new null terminator character
  end[1] = '\0';

  return str;
}

Se você não pode modificar a cadeia, então você pode usar basicamente o mesmo método:

// Stores the trimmed input string into the given output buffer, which must be
// large enough to store the result.  If it is too small, the output is
// truncated.
size_t trimwhitespace(char *out, size_t len, const char *str)
{
  if(len == 0)
    return 0;

  const char *end;
  size_t out_size;

  // Trim leading space
  while(isspace((unsigned char)*str)) str++;

  if(*str == 0)  // All spaces?
  {
    *out = 0;
    return 1;
  }

  // Trim trailing space
  end = str + strlen(str) - 1;
  while(end > str && isspace((unsigned char)*end)) end--;
  end++;

  // Set output size to minimum of trimmed string length and buffer size minus 1
  out_size = (end - str) < len-1 ? (end - str) : len-1;

  // Copy trimmed string and add null terminator
  memcpy(out, str, out_size);
  out[out_size] = 0;

  return out_size;
}

Outras dicas

Aqui está um que muda a seqüência na primeira posição do seu buffer. Você pode querer esse comportamento para que se alocada dinamicamente a corda, você ainda pode libertá-la no mesmo ponteiro que a guarnição () retorna:

char *trim(char *str)
{
    size_t len = 0;
    char *frontp = str;
    char *endp = NULL;

    if( str == NULL ) { return NULL; }
    if( str[0] == '\0' ) { return str; }

    len = strlen(str);
    endp = str + len;

    /* Move the front and back pointers to address the first non-whitespace
     * characters from each end.
     */
    while( isspace((unsigned char) *frontp) ) { ++frontp; }
    if( endp != frontp )
    {
        while( isspace((unsigned char) *(--endp)) && endp != frontp ) {}
    }

    if( str + len - 1 != endp )
            *(endp + 1) = '\0';
    else if( frontp != str &&  endp == frontp )
            *str = '\0';

    /* Shift the string so that it starts at str so that if it's dynamically
     * allocated, we can still free it on the returned pointer.  Note the reuse
     * of endp to mean the front of the string buffer now.
     */
    endp = str;
    if( frontp != str )
    {
            while( *frontp ) { *endp++ = *frontp++; }
            *endp = '\0';
    }


    return str;
}

Test para correção:

int main(int argc, char *argv[])
{
    char *sample_strings[] =
    {
            "nothing to trim",
            "    trim the front",
            "trim the back     ",
            " trim one char front and back ",
            " trim one char front",
            "trim one char back ",
            "                   ",
            " ",
            "a",
            "",
            NULL
    };
    char test_buffer[64];
    int index;

    for( index = 0; sample_strings[index] != NULL; ++index )
    {
            strcpy( test_buffer, sample_strings[index] );
            printf("[%s] -> [%s]\n", sample_strings[index],
                                     trim(test_buffer));
    }

    /* The test prints the following:
    [nothing to trim] -> [nothing to trim]
    [    trim the front] -> [trim the front]
    [trim the back     ] -> [trim the back]
    [ trim one char front and back ] -> [trim one char front and back]
    [ trim one char front] -> [trim one char front]
    [trim one char back ] -> [trim one char back]
    [                   ] -> []
    [ ] -> []
    [a] -> [a]
    [] -> []
    */

    return 0;
}

O arquivo de origem foi trim.c. Compilado com 'cc trim.c -o cortar'.

A minha solução. String deve ser mutável. A vantagem acima algumas das outras soluções que se move a parte não-espaço ao início para que você possa continuar usando o ponteiro antigo, caso você tem que libertar ()-lo mais tarde.

void trim(char * s) {
    char * p = s;
    int l = strlen(p);

    while(isspace(p[l - 1])) p[--l] = 0;
    while(* p && isspace(* p)) ++p, --l;

    memmove(s, p, l + 1);
}   

Esta versão cria uma cópia do string com strndup () em vez de editá-lo no lugar. strndup () requer _GNU_SOURCE, talvez por isso que você precisa para fazer o seu próprio strndup () com malloc () e strncpy ().

char * trim(char * s) {
    int l = strlen(s);

    while(isspace(s[l - 1])) --l;
    while(* s && isspace(* s)) ++s, --l;

    return strndup(s, l);
}

Aqui está minha biblioteca C mini-para aparar esquerda, direita, ambos, tudo, no lugar e separado, e aparar um conjunto de caracteres especificados (ou espaço em branco por padrão).

conteúdo de strlib.h:

#ifndef STRLIB_H_
#define STRLIB_H_ 1
enum strtrim_mode_t {
    STRLIB_MODE_ALL       = 0, 
    STRLIB_MODE_RIGHT     = 0x01, 
    STRLIB_MODE_LEFT      = 0x02, 
    STRLIB_MODE_BOTH      = 0x03
};

char *strcpytrim(char *d, // destination
                 char *s, // source
                 int mode,
                 char *delim
                 );

char *strtriml(char *d, char *s);
char *strtrimr(char *d, char *s);
char *strtrim(char *d, char *s); 
char *strkill(char *d, char *s);

char *triml(char *s);
char *trimr(char *s);
char *trim(char *s);
char *kill(char *s);
#endif

conteúdo de strlib.c:

#include <strlib.h>

char *strcpytrim(char *d, // destination
                 char *s, // source
                 int mode,
                 char *delim
                 ) {
    char *o = d; // save orig
    char *e = 0; // end space ptr.
    char dtab[256] = {0};
    if (!s || !d) return 0;

    if (!delim) delim = " \t\n\f";
    while (*delim) 
        dtab[*delim++] = 1;

    while ( (*d = *s++) != 0 ) { 
        if (!dtab[0xFF & (unsigned int)*d]) { // Not a match char
            e = 0;       // Reset end pointer
        } else {
            if (!e) e = d;  // Found first match.

            if ( mode == STRLIB_MODE_ALL || ((mode != STRLIB_MODE_RIGHT) && (d == o)) ) 
                continue;
        }
        d++;
    }
    if (mode != STRLIB_MODE_LEFT && e) { // for everything but trim_left, delete trailing matches.
        *e = 0;
    }
    return o;
}

// perhaps these could be inlined in strlib.h
char *strtriml(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_LEFT, 0); }
char *strtrimr(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_RIGHT, 0); }
char *strtrim(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_BOTH, 0); }
char *strkill(char *d, char *s) { return strcpytrim(d, s, STRLIB_MODE_ALL, 0); }

char *triml(char *s) { return strcpytrim(s, s, STRLIB_MODE_LEFT, 0); }
char *trimr(char *s) { return strcpytrim(s, s, STRLIB_MODE_RIGHT, 0); }
char *trim(char *s) { return strcpytrim(s, s, STRLIB_MODE_BOTH, 0); }
char *kill(char *s) { return strcpytrim(s, s, STRLIB_MODE_ALL, 0); }

A única rotina principal faz tudo. Ele corta no lugar, se src == dst , caso contrário, ele funciona como as rotinas strcpy. Ele corta um conjunto de caracteres especificado na cadeia delim , ou espaço em branco se nulo. Ele corta a esquerda, direita, ambos, e tudo (como tr). Não há muito a ele, e ele itera sobre a corda apenas uma vez. Algumas pessoas podem reclamar que começa logo guarnição do lado esquerdo, no entanto, não strlen é necessário que começa à esquerda de qualquer maneira. (De uma forma ou outra você tem que chegar ao fim da cadeia de guarnições certas, então você pode muito bem fazer o trabalho que você vá.) Pode haver argumentos a serem feitas sobre tamanhos de pipelining e cache e tal - quem sabe . Desde as obras de soluções da esquerda para a direita e repete apenas uma vez, ele pode ser expandido para o trabalho em fluxos bem. Limitações:. Ele faz não trabalho em unicode cordas

Aqui é a minha tentativa de uma simples, mas a função caimento correto no local.

void trim(char *str)
{
    int i;
    int begin = 0;
    int end = strlen(str) - 1;

    while (isspace((unsigned char) str[begin]))
        begin++;

    while ((end >= begin) && isspace((unsigned char) str[end]))
        end--;

    // Shift all characters back to the start of the string array.
    for (i = begin; i <= end; i++)
        str[i - begin] = str[i];

    str[i - begin] = '\0'; // Null terminate string.
}

atrasado para a festa guarnição

Características:
1. Apare o início rapidamente, como em uma série de outras respostas.
2. Depois de ir até o fim, aparando a direita com apenas 1 teste por loop. Como @ jfm3, mas trabalha para uma seqüência de todos os espaços em branco)
3. Para evitar um comportamento indefinido quando char é um char assinado, *s convertido para unsigned char.

manipulação de caracteres "Em todos os casos, o argumento é uma int, cujo valor será representável como um unsigned char ou será igual ao valor do EOF macro. Se o argumento tem qualquer outro valor, o comportamento é indefinido." C11 §7.4 1

#include <ctype.h>

// Return a pointer to the trimmed string
char *string_trim_inplace(char *s) {
  while (isspace((unsigned char) *s)) s++;
  if (*s) {
    char *p = s;
    while (*p) p++;
    while (isspace((unsigned char) *(--p)));
    p[1] = '\0';
  }

  // If desire to shift the trimmed string

  return s;
}

@chqrlie comentou o acima não muda a corda cortada. Para fazê-lo ....

// Return a pointer to the (shifted) trimmed string
char *string_trim_inplace(char *s) {
  char *original = s;
  size_t len = 0;

  while (isspace((unsigned char) *s)) {
    s++;
  } 
  if (*s) {
    char *p = s;
    while (*p) p++;
    while (isspace((unsigned char) *(--p)));
    p[1] = '\0';
    len = (size_t) (p - s);
  }

  return (s == original) ? s : memove(original, s, len + 1);
}

Aqui está uma solução semelhante à @ Adam-rosenfields rotina modificação no local, mas sem desnecessariamente recorrer a strlen (). Como @jkramer, a string é deixado ajustado dentro do buffer para que possa libertar o mesmo ponteiro. Não ideal para grandes cadeias, uma vez que não usa memmove. Inclui os ++ / - operadores que @ jfm3 menciona. FCTX baseado testes de unidade incluídos.

#include <ctype.h>

void trim(char * const a)
{
    char *p = a, *q = a;
    while (isspace(*q))            ++q;
    while (*q)                     *p++ = *q++;
    *p = '\0';
    while (p > a && isspace(*--p)) *p = '\0';
}

/* See http://fctx.wildbearsoftware.com/ */
#include "fct.h"

FCT_BGN()
{
    FCT_QTEST_BGN(trim)
    {
        { char s[] = "";      trim(s); fct_chk_eq_str("",    s); } // Trivial
        { char s[] = "   ";   trim(s); fct_chk_eq_str("",    s); } // Trivial
        { char s[] = "\t";    trim(s); fct_chk_eq_str("",    s); } // Trivial
        { char s[] = "a";     trim(s); fct_chk_eq_str("a",   s); } // NOP
        { char s[] = "abc";   trim(s); fct_chk_eq_str("abc", s); } // NOP
        { char s[] = "  a";   trim(s); fct_chk_eq_str("a",   s); } // Leading
        { char s[] = "  a c"; trim(s); fct_chk_eq_str("a c", s); } // Leading
        { char s[] = "a  ";   trim(s); fct_chk_eq_str("a",   s); } // Trailing
        { char s[] = "a c  "; trim(s); fct_chk_eq_str("a c", s); } // Trailing
        { char s[] = " a ";   trim(s); fct_chk_eq_str("a",   s); } // Both
        { char s[] = " a c "; trim(s); fct_chk_eq_str("a c", s); } // Both

        // Villemoes pointed out an edge case that corrupted memory.  Thank you.
        // http://stackoverflow.com/questions/122616/#comment23332594_4505533
        {
          char s[] = "a     ";       // Buffer with whitespace before s + 2
          trim(s + 2);               // Trim "    " containing only whitespace
          fct_chk_eq_str("", s + 2); // Ensure correct result from the trim
          fct_chk_eq_str("a ", s);   // Ensure preceding buffer not mutated
        }

        // doukremt suggested I investigate this test case but
        // did not indicate the specific behavior that was objectionable.
        // http://stackoverflow.com/posts/comments/33571430
        {
          char s[] = "         foobar";  // Shifted across whitespace
          trim(s);                       // Trim
          fct_chk_eq_str("foobar", s);   // Leading string is correct

          // Here is what the algorithm produces:
          char r[16] = { 'f', 'o', 'o', 'b', 'a', 'r', '\0', ' ',                     
                         ' ', 'f', 'o', 'o', 'b', 'a', 'r', '\0'};
          fct_chk_eq_int(0, memcmp(s, r, sizeof(s)));
        }
    }
    FCT_QTEST_END();
}
FCT_END();

Outra, com uma linha fazendo o trabalho real:

#include <stdio.h>

int main()
{
   const char *target = "   haha   ";
   char buf[256];
   sscanf(target, "%s", buf); // Trimming on both sides occurs here
   printf("<%s>\n", buf);
}

Eu não o fez como a maioria destas respostas, porque eles fizeram um ou mais dos seguintes ...

  1. Obtivemos um ponteiro diferente dentro corda do ponteiro de origem (um tipo de dor que fazer malabarismos dois ponteiros diferentes para a mesma coisa).
  2. Made uso gratuito de coisas como strlen () que a pré-iterate toda a string.
  3. funções lib específicos OS-não-portátil usado.
  4. Backscanned.
  5. a comparação utilizada a ' ' em vez de isspace () para que TAB / CR / LF são preservados.
  6. memória desperdiçado com buffers grande estáticos.
  7. ciclos de desperdício com funções de alto custo como sscanf / sprintf .

Aqui é a minha versão:

void fnStrTrimInPlace(char *szWrite) {

    const char *szWriteOrig = szWrite;
    char       *szLastSpace = szWrite, *szRead = szWrite;
    int        bNotSpace;

    // SHIFT STRING, STARTING AT FIRST NON-SPACE CHAR, LEFTMOST
    while( *szRead != '\0' ) {

        bNotSpace = !isspace((unsigned char)(*szRead));

        if( (szWrite != szWriteOrig) || bNotSpace ) {

            *szWrite = *szRead;
            szWrite++;

            // TRACK POINTER TO LAST NON-SPACE
            if( bNotSpace )
                szLastSpace = szWrite;
        }

        szRead++;
    }

    // TERMINATE AFTER LAST NON-SPACE (OR BEGINNING IF THERE WAS NO NON-SPACE)
    *szLastSpace = '\0';
}

Muito tarde para a festa ...

Single-Pass solução sem retrocesso para a frente-digitalizar. Cada personagem na cadeia de origem é testado exatamente , uma vez duas vezes. (Por isso, deve ser mais rápido do que a maioria das outras soluções aqui, especialmente se a cadeia de origem tem um monte de espaços à direita.)

Isto inclui duas soluções, uma para copiar e aparar uma cadeia de origem para uma outra corda destino e outro para cortar a cadeia de origem no lugar. Ambas as funções usam o mesmo código.

A (modificável) string é movida no local, de modo que o ponteiro original permanece inalterado.

#include <stddef.h>
#include <ctype.h>

char * trim2(char *d, const char *s)
{
    // Sanity checks
    if (s == NULL  ||  d == NULL)
        return NULL;

    // Skip leading spaces        
    const unsigned char * p = (const unsigned char *)s;
    while (isspace(*p))
        p++;

    // Copy the string
    unsigned char * dst = (unsigned char *)d;   // d and s can be the same
    unsigned char * end = dst;
    while (*p != '\0')
    {
        if (!isspace(*dst++ = *p++))
            end = dst;
    }

    // Truncate trailing spaces
    *end = '\0';
    return d;
}

char * trim(char *s)
{
    return trim2(s, s);
}

Eu não tenho certeza do que você considera "indolor".

cordas

C são muito doloroso. Nós podemos encontrar a primeira posição do caractere não-espaço em branco trivialmente:

while (isspace(* p)) p++;

Podemos encontrar a posição do carácter última não-espaço em branco com dois movimentos triviais semelhantes:

while (* q) q++;
do { q--; } while (isspace(* q));

(poupei-lhe a dor de usar os operadores * e ++ ao mesmo tempo.)

A questão agora é o que você faz com isso? O tipo de dados em mãos não é realmente um grande String abstrato robusto que é fácil pensar, mas em vez realmente mal mais do que uma matriz de bytes de armazenamento. Na falta de um tipo de dados robusta, é impossível escrever uma função que irá fazer o mesmo que a função chomp de PHperytonby. O que seria uma tal função em C retorno?

Use a biblioteca corda , por exemplo:

Ustr *s1 = USTR1(\7, " 12345 ");

ustr_sc_trim_cstr(&s1, " ");
assert(ustr_cmp_cstr_eq(s1, "12345"));

... como você dizer que este é um problema "comum", sim, você precisa incluir um #include ou assim e não está incluído no libc, mas não vão inventar seu próprio hack trabalho armazenar ponteiros aleatórios e size_t é assim apenas conduz à sobrecarga de memória.

#include "stdafx.h"
#include "malloc.h"
#include "string.h"

int main(int argc, char* argv[])
{

  char *ptr = (char*)malloc(sizeof(char)*30);
  strcpy(ptr,"            Hel  lo    wo           rl   d G    eo rocks!!!    by shahil    sucks b i          g       tim           e");

  int i = 0, j = 0;

  while(ptr[j]!='\0')
  {

      if(ptr[j] == ' ' )
      {
          j++;
          ptr[i] = ptr[j];
      }
      else
      {
          i++;
          j++;
          ptr[i] = ptr[j];
      }
  }


  printf("\noutput-%s\n",ptr);
        return 0;
}

s era tão extremamente útil, eu queria dizer que eu estava feliz este post estava disponível e para mostrar o que eu era capaz de fazer com os exemplos. Eu precisava tokenizar uma seqüência maior, e depois tome a substring (s) e encontrar o último - para que eu pudesse remover uma nova linha de fgets () chamada, e também remover o espaço em branco da frente do que simbólica - para que eu pudesse facilmente compará-lo com uma corda estática. O primeiro exemplo no post acima de mim ficou lá, então obrigado. Aqui está como eu usei os exemplos de código e a saída que eu tenho.

int _tmain(int argc, _TCHAR* argv[])
{
   FILE * fp;   // test file
   char currDBSStatstr[100] = {"/0"};
   char *beg;
   char *end;
   char *str1;
   char str[] = "Initializing DBS Configuration";
   fp = fopen("file2-1.txt","r");
   if (fp != NULL)
   {
      printf("File exists.\n");
      fgets(currDBSStatstr, sizeof(currDBSStatstr), fp);
   }
   else
   {
      printf("Error.\n");
      exit(2);
   }  
   //print string
   printf("String: %s\n", currDBSStatstr);
   //extract first string
   str1 = strtok(currDBSStatstr, ":-");
   //print first token
   printf("%s\n", str1);
   //get more tokens in sequence
   while(1)
   {
      //extract more tokens in sequence
      str1 = strtok(NULL, ":-");
      //check to see if done
      if (str1 == NULL)
      {
         printf("Tokenizing Done.\n");
         exit(0);
      }
      //print string after tokenizing Done
      printf("%s\n", str1);
      end = str1 + strlen(str1) - 1;
      while((end > str1) && (*end == '\n'))
      {
         end--;
         *(end+1) = 0;
         beg = str1;
         while(isspace(*str1))
            str1++;
      }
      printf("%s\n", str1);
      if (strcmp(str, str1) == 0)
         printf("Strings are equal.\n");
   }
   return 0;

}

saída

O arquivo já existe.

Cordas: Estado DBS: DBS Startup - Configuração DBS Inicialização

Estado DBS

DBS Startup

DBS Startup

Configuração DBS Inicialização

Configuração DBS Inicialização

Strings são iguais.

tokenizing Concluído.

Se você estiver usando glib, então você pode usar g_strstrip

Apenas para manter este crescimento, mais uma opção com uma corda modificável:

void trimString(char *string)
{
    size_t i = 0, j = strlen(string);
    while (j > 0 && isspace((unsigned char)string[j - 1])) string[--j] = '\0';
    while (isspace((unsigned char)string[i])) i++;
    if (i > 0) memmove(string, string + i, j - i + 1);
}

Eu sei que tem muitas respostas, mas eu postar minha resposta aqui para ver se a minha solução é bom o suficiente.

// Trims leading whitespace chars in left `str`, then copy at almost `n - 1` chars
// into the `out` buffer in which copying might stop when the first '\0' occurs, 
// and finally append '\0' to the position of the last non-trailing whitespace char.
// Reture the length the trimed string which '\0' is not count in like strlen().
size_t trim(char *out, size_t n, const char *str)
{
    // do nothing
    if(n == 0) return 0;    

    // ptr stop at the first non-leading space char
    while(isspace(*str)) str++;    

    if(*str == '\0') {
        out[0] = '\0';
        return 0;
    }    

    size_t i = 0;    

    // copy char to out until '\0' or i == n - 1
    for(i = 0; i < n - 1 && *str != '\0'; i++){
        out[i] = *str++;
    }    

    // deal with the trailing space
    while(isspace(out[--i]));    

    out[++i] = '\0';
    return i;
}

A maneira mais fácil de ignorar espaços à esquerda em uma string é, IMHO,

#include <stdio.h>

int main()
{
char *foo="     teststring      ";
char *bar;
sscanf(foo,"%s",bar);
printf("String is >%s<\n",bar);
    return 0;
}

Ok esta é a minha opinião sobre a questão. Eu acredito que é a solução mais concisa que modifica a corda no lugar (free vai funcionar) e evita qualquer UB. Para as pequenas cordas, é provavelmente mais rápido do que um memmove envolvendo solução.

void stripWS_LT(char *str)
{
    char *a = str, *b = str;
    while (isspace((unsigned char)*a)) a++;
    while (*b = *a++)  b++;
    while (b > str && isspace((unsigned char)*--b)) *b = 0;
}
#include <ctype.h>
#include <string.h>

char *trim_space(char *in)
{
    char *out = NULL;
    int len;
    if (in) {
        len = strlen(in);
        while(len && isspace(in[len - 1])) --len;
        while(len && *in && isspace(*in)) ++in, --len;
        if (len) {
            out = strndup(in, len);
        }
    }
    return out;
}

isspace ajuda a cortar todos os espaços em branco.

  • Executar um primeiro ciclo de verificar do último byte por caractere de espaço e reduzir a variável comprimento
  • Execute um segundo circuito para verificar a partir de primeiro byte para o carácter de espaço e reduzir o comprimento variável e ponteiro de char incremento.
  • Finalmente, se variável comprimento é mais do que 0, então use strndup para criar novo buffer de string, excluindo espaços.

Pessoalmente, eu fazer a minha própria. Você pode usar strtok, mas você precisa tomar cuidado com isso (especialmente se você está removendo personagens principais) que você sabe o que a memória é o que.

Livrar-se de espaços à direita é fácil, e bastante seguro, como você pode apenas colocar um 0 em cima do topo do último espaço, contagem de volta a partir do final. Livrar-se dos principais espaços meios mover as coisas. Se você quiser fazê-lo no lugar (provavelmente sensível) você pode apenas manter mudando tudo de volta um personagem até que não há espaço à esquerda. Ou, para ser mais eficiente, você pode encontrar o índice do primeiro caractere não-espaço, e mudança de tudo de volta por esse número. Ou, você pode simplesmente usar um ponteiro para o primeiro caractere não-espaço (mas então você precisa ter cuidado, da mesma forma como você faz com strtok).

Um pouco tarde para o jogo, mas vou jogar minhas rotinas para a briga. Eles são provavelmente não o mais eficiente em termos absolutos, mas acredito que eles estão corretos e eles são simples (com rtrim() empurrando o envelope complexidade):

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

A maioria das respostas até agora fazer um dos seguintes procedimentos:

  1. Backtrack no final da cadeia (ou seja, encontrar o fim da corda e em seguida, procurar para trás até que um caractere não-espaço é encontrado,) ou
  2. Chamada strlen() em primeiro lugar, fazer uma segunda passagem através de toda a string.

Esta versão faz apenas uma passagem e não recuar. Por isso, pode ter um melhor desempenho do que os outros, mas apenas se é comum ter centenas de espaços à direita (que não é incomum quando se lida com a saída de uma consulta 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';
}

Este é o mais curto possível implementação posso pensar em:

static const char *WhiteSpace=" \n\r\t";
char* trim(char *t)
{
    char *e=t+(t!=NULL?strlen(t):0);               // *e initially points to end of string
    if (t==NULL) return;
    do --e; while (strchr(WhiteSpace, *e) && e>=t);  // Find last char that is not \r\n\t
    *(++e)=0;                                      // Null-terminate
    e=t+strspn (t,WhiteSpace);                           // Find first char that is not \t
    return e>t?memmove(t,e,strlen(e)+1):t;                  // memmove string contents and terminator
}

Estas funções irão modificar o buffer original, por isso, se alocada dinamicamente, o original ponteiro pode ser liberado.

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

O que você acha sobre o uso da função StrTrim definido no cabeçalho Shlwapi.h.? É para a frente em vez definindo em seu próprio país.
Detalhes podem ser encontrados em:
http://msdn.microsoft. com / en-us / library / janelas / desktop / bb773454 (v = VS.85) .aspx

Se você tem
char ausCaptain[]="GeorgeBailey ";
StrTrim(ausCaptain," ");
Isto vai dar ausCaptain como "GeorgeBailey" não "GeorgeBailey ".

Para cortar minhas cordas de ambos os lados eu uso o oldie mas o gooody;) Ele pode cortar qualquer coisa com ascii menos do que um espaço, o que significa que os caracteres de controle serão aparadas também!

char *trimAll(char *strData)
{
  unsigned int L = strlen(strData);
  if(L > 0){ L--; }else{ return strData; }
  size_t S = 0, E = L;
  while((!(strData[S] > ' ') || !(strData[E] > ' ')) && (S >= 0) && (S <= L) && (E >= 0) && (E <= L))
  {
    if(strData[S] <= ' '){ S++; }
    if(strData[E] <= ' '){ E--; }
  }
  if(S == 0 && E == L){ return strData; } // Nothing to be done
  if((S >= 0) && (S <= L) && (E >= 0) && (E <= L)){
    L = E - S + 1;
    memmove(strData,&strData[S],L); strData[L] = '\0';
  }else{ strData[0] = '\0'; }
  return strData;
}

Eu só estou incluindo o código porque o código postado até agora parece abaixo do ideal (e eu não tenho o representante para comentários.)

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() é uma extensão GNU. Se você não tê-lo ou algo equivalente, rolar o seu próprio. Por exemplo:

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

Aqui eu uso a alocação de memória dinâmica para cortar a cadeia de entrada para o trimStr função. Primeiro, encontramos quantos existem caracteres não-vazios na cadeia de entrada. Então, alocamos um array de caracteres com esse tamanho e cuidar do caractere nulo encerrado. Quando utilizar esta função, é preciso libertar o interior da memória da função principal.

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

Aqui está como eu faço isso. Ele corta a corda no lugar, por isso não se preocupar com desalocá uma cadeia devolvida ou perder o ponteiro para uma string alocada. Pode não ser a resposta mais curto possível, mas deve ficar claro para a maioria dos leitores.

#include <ctype.h>
#include <string.h>
void trim_str(char *s)
{
    const size_t s_len = strlen(s);

    int i;
    for (i = 0; i < s_len; i++)
    {
        if (!isspace( (unsigned char) s[i] )) break;
    }

    if (i == s_len)
    {
        // s is an empty string or contains only space characters

        s[0] = '\0';
    }
    else
    {
        // s contains non-space characters

        const char *non_space_beginning = s + i;

        char *non_space_ending = s + s_len - 1;
        while ( isspace( (unsigned char) *non_space_ending ) ) non_space_ending--;

        size_t trimmed_s_len = non_space_ending - non_space_beginning + 1;

        if (s != non_space_beginning)
        {
            // Non-space characters exist in the beginning of s

            memmove(s, non_space_beginning, trimmed_s_len);
        }

        s[trimmed_s_len] = '\0';
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top