Frage

Gibt es eine saubere, vorzugsweise Standardmethode zum Entfernen führender und nachfolgender Leerzeichen aus einer Zeichenfolge in C?Ich würde mein eigenes rollen, aber ich denke, dass dies ein häufiges Problem ist, für das es eine ebenso häufige Lösung gibt.

War es hilfreich?

Lösung

Wenn Sie die Zeichenfolge ändern können:

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

Wenn Sie die Zeichenfolge nicht ändern können, dann können Sie im Grunde die gleiche Methode verwenden:

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

Andere Tipps

Hier ist eine, die die Zeichenfolge in die erste Position des Puffers verschiebt. Sie können dieses Verhalten wollen, so dass, wenn Sie dynamisch die Zeichenfolge zugewiesen, Sie immer noch auf dem gleichen Zeiger befreien können, die trim () zurückgibt:

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 für Richtigkeit:

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

Die Quelldatei war trim.c. Zusammengestellt mit 'cc trim.c -o trimmen'.

Meine Lösung. String muss veränderbar sein. Der Vorteil über einige der anderen Lösungen, die es den nicht-Raumteil zu Beginn bewegt, so dass Sie die alten Zeiger mit halten können, falls Sie zu befreien haben () es später.

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

Diese Version erstellt eine Kopie des Strings mit strndup () statt es anstelle der Bearbeitung. strndup () erfordert _GNU_SOURCE, vielleicht müssen Sie Ihre eigene strndup () mit malloc () und strncpy () machen.

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

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

    return strndup(s, l);
}

Hier ist meine C Mini-Bibliothek für links Trimmen, rechts, beide, alle, an Ort und Stelle und zu trennen, und eine Reihe von angegebenen Zeichen Trimmen (oder Leerraum in der Standardeinstellung).

Inhalte 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

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

Die eine Hauptroutine tut alles. Es schneidet in Kraft, wenn src == dst , sonst, es funktioniert wie die strcpy Routinen. Es schneidet eine Reihe von Zeichen in der Zeichenfolge angegebene delim oder Leerraum wenn null. Es trimmt links, rechts, beide, und alle (wie tr). Es gibt nicht viel zu ihm, und es durchläuft nur einmal die Schnur über. Einige Leute könnten sich beschweren, dass rechts beginnt auf der linken Seite trimmen, jedoch keine Strlen benötigt, die ohnehin auf der linken Seite beginnt. (Eine oder andere Weise haben Sie für richtig trimmt das Ende der Schnur zu bekommen, so dass Sie könnte die Arbeit auch tun, wie Sie gehen.) Es gibt Argumente sein kann über Pipelining und Cache-Größen und so gemacht werden - wer weiß, . Da die Lösung nur von links nach rechts und iteriert arbeitet einmal, es kann erweitert werden, als auch auf Ströme zu arbeiten. Einschränkungen:. Es hat nicht Arbeit Unicode Strings

Hier ist mein Versuch eines einfachen, aber richtig in-Place-Trimm-Funktion.

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

Späte an der Trimmung Partei

Eigenschaften:
 1. Schneiden Sie den Anfang schnell, wie es in einer Reihe von anderen Antworten.
 2. Nach dem bis zum Ende gehen, das Recht, mit nur 1 Test pro Schleife trimmen. Wie @ jfm3, sondern arbeitet für ein All white-space string)
 3. Um undefinierte Verhalten zu vermeiden, wenn char ein signiertes char, Guss *s ist zu unsigned char.

  

Zeichenbehandlung „In allen Fällen das Argument ein int, so wird der Wert als ein unsigned char darstellbarer oder hat den Wert des Makros EOF gleich. Wenn das Argument einen anderen Wert hat, das Verhalten ist nicht definiert.“ 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 die oben kommentiert nicht die getrimmte Zeichenfolge verschieben. Um dies zu tun ....

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

Hier ist eine Lösung ähnlich wie @ adam-rosenfields in-Place-Modifikationsroutine aber ohne unnötig Strlen greifen (). Wie @jkramer, wird die Zeichenfolge im Puffer-links eingestellt, so dass Sie den gleichen Zeiger frei. Nicht optimal für große Strings, da es nicht memmove nicht verwendet. Enthält die ++ / - Operatoren, die @ jfm3 erwähnt. FCTX -basierte Unit-Tests enthalten.

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

Ein weiterer, mit einer Linie, die die eigentliche Arbeit tun:

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

Ich habe nicht wie die meisten dieser Antworten, weil sie tat oder mehrere der folgenden ...

  1. Retour einen anderen Zeiger in der Zeichenfolge des ursprünglichen Zeigers (eine Art Schmerz zwei verschiedene Zeiger auf die gleiche Sache zu jonglieren).
  2. Made unentgeltliche Nutzung von Dingen wie strlen () , dass die gesamte Zeichenfolge vorgelaufen.
  3. Gebrauchte nicht-portable OS-spezifische Funktionen lib.
  4. Backscanned.
  5. Gebrauchte Vergleich zu ‘‚ statt isspace () , so dass TAB / CR / LF beibehalten.
  6. vergeudet Speicher mit großen statischen Puffer.
  7. vergeudeten Zyklen mit hohen Kostenfunktionen wie sscanf / sprintf .

Hier ist meine Version:

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

Sehr spät zur Party...

Single-Pass-Vorwärtsscanlösung ohne Backtracking.Jedes Zeichen im Quellstring wird genau getestet einmal zweimal.(Es sollte also schneller sein als die meisten anderen Lösungen hier, insbesondere wenn die Quellzeichenfolge viele abschließende Leerzeichen enthält.)

Dazu gehören zwei Lösungen: eine zum Kopieren und Zuschneiden einer Quellzeichenfolge in eine andere Zielzeichenfolge und die andere zum Zuschneiden der Quellzeichenfolge an Ort und Stelle.Beide Funktionen verwenden denselben Code.

Die (veränderbare) Zeichenfolge wird an Ort und Stelle verschoben, sodass der ursprüngliche Zeiger darauf unverändert bleibt.

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

Ich bin nicht sicher, was Sie als „schmerzlos.“

C-Strings sind ziemlich schmerzhaft. Wir können die erste Nicht-Leerzeichen Position finden triviale:

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

Wir können die letzte Nicht-Leerzeichen Position mit zwei ähnlichen trivial bewegt finden:

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

(ich habe erspart Ihnen den Schmerz der Verwendung der * und ++ Betreiber zugleich.)

Die Frage ist nun, was tun Sie mit diesem? Der Datentyp bei der Hand ist nicht wirklich ein großes robustes abstraktes String, die über leicht zu denken ist, sondern wirklich kaum mehr als ein Array von Speichern Bytes. In Ermangelung eines robusten Datentyp, ist es unmöglich, eine Funktion zu schreiben, die die gleiche wie PHperytonby der chomp Funktion tun wird. Was würde eine solche Funktion in C zurückkehren?

String-Bibliothek rel="nofollow, zum Beispiel:

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

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

... wie Sie sagen, dass dies ein „gemeinsames“ Problem ist, ja müssen Sie eine #include enthalten oder so und es ist nicht in libc enthalten, aber gehen Sie nicht Ihren eigenen Hack Job speichern Zufall Zeiger zu erfinden und size_t ist auf diese Weise führt nur einen Pufferüberlauf.

#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 war so extrem hilfreich, ich war ich froh, dieser Beitrag zur Verfügung steht und zu zeigen, was ich war in der Lage zu tun, mit den Beispielen sagen wollte. Ich brauchte einen größeren String tokenize, und nehmen Sie dann den Teil (n) und finden Sie die letzten - so konnte ich eine neue Zeile von fgets () -Aufruf, entfernen und auch den Leerraum von der Vorderseite dieses Token entfernen - so konnte ich einfach vergleicht es mit einem statischen String. Das erste Beispiel in der Zeit nach oben hat mich dort, so danke. Hier ist, wie ich die Codebeispiele verwendet und die Ausgabe ich habe.

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;

}

Output

  

Datei existiert.

     

String: DBS-Zustand: DBS Inbetriebnahme - Initialisierung DBS Konfiguration

     

DBS Staat

     

DBS Startup

     

DBS Startup

     

Initializing DBS Konfiguration

     

Initializing DBS Konfiguration

     

Strings gleich sind.

     

Tokenizing Fertig.

Wenn Sie glib verwenden, dann können Sie g_strstrip

Just halten diese wachsende, eine weitere Option mit einem änderbaren string:

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

Ich weiß, dass es viele Antworten, aber ich poste meine Antwort hier, um zu sehen, ob meine Lösung gut genug ist.

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

Der einfachste Weg, Räume in einem String zu überspringen führt, ist, imho,

#include <stdio.h>

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

Ok das ist mein nehmen auf die Frage. Ich glaube, es ist die prägnanteste Lösung, die die Zeichenfolge an Ort und Stelle modifiziert (free funktioniert) und vermeidet UB. Für kleine Strings, dann ist es wahrscheinlich schneller als eine Lösung beteiligt memmove.

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 hilft, alle weißen Flächen zu trimmen.

  • Führen Sie eine erste Schleife von den letzten Byte für Leerzeichen zu überprüfen und die Länge variabel
  • reduzieren
  • Ausführen eine zweite Schleife vom ersten Byte für Leerzeichen zu überprüfen und um die Länge und variable inkrementiert char pointer reduzieren.
  • Schließlich, wenn die Länge Variable mehr als 0 ist, dann strndup verwenden, um neuen String-Puffer zu schaffen durch Leerzeichen auszuschließen.

Ich persönlich würde meine eigene Rolle. Sie können strtok verwenden, aber Sie müssen darauf achten, mit so tun (vor allem, wenn Sie führende Zeichen sind zu entfernen), dass Sie wissen, welche Speicher, was ist.

von Leerzeichen Loswerden ist einfach und ziemlich sicher, da Sie nur ein 0 in über die Spitze des letzten Raumes setzen, von dem Ende zu zählen zurück. Loswerden von führenden Leerzeichen bedeutet, die Dinge bewegen. Wenn Sie es an Ort und Stelle (wahrscheinlich sinnvoll) tun mögen, können Sie einfach immer alles ein Zeichen zurück verschieben, bis es kein führender Raum ist. Oder effizienter sein, können Sie den Index des ersten Nicht-Leerzeichen finden können, und verschieben alles wieder von dieser Zahl. Oder Sie könnten nur einen Zeiger auf den ersten Nicht-Leerzeichen verwenden (aber dann müssen Sie auf die gleiche Art und Weise vorsichtig sein, wie Sie mit strtok tun).

Ein bisschen spät, um das Spiel, aber ich werde meine Routinen in den Kampf werfen. Sie sind wahrscheinlich nicht die absolut effizient, aber ich glaube, sie sind richtig und sie sind einfach (mit rtrim() die Komplexität Umschlag schieben):

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

Die meisten Antworten weit, so wählen Sie eine der folgenden Möglichkeiten:

  1. Backtrack am Ende der Schnur (das heißt das Ende der Zeichenfolge finden und dann versuchen, nach hinten, bis ein Nicht-Leerzeichen gefunden wird,) oder
  2. Rufen Sie strlen() ersten, einen zweiten Durchlauf durch die ganze Reihe zu machen.

Diese Version macht nur einen Durchgang und Rückzieher nicht. Daher kann es eine bessere Leistung als die anderen, allerdings nur, wenn es gemeinsam Hunderte von Leerzeichen am Ende zu haben (was nicht ungewöhnlich ist, wenn sie mit dem Ausgang einer SQL-Abfrage zu tun.)

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

Dies ist die kürzestmögliche Implementierung ich mir vorstellen kann:

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
}

Diese Funktionen werden die ursprünglichen Puffer ändern, so dass, wenn dynamisch zugewiesen, das Original Zeiger kann befreit werden.

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

Was denken Sie über StrTrim Funktion definiert in Header Shlwapi.h.? Es ist gerade nach vorne eher definieren auf eigene Faust.
Details kann auch gefunden werden:
  http://msdn.microsoft. com / en-us / library / windows / Desktop / bb773454 (v = VS.85) aspx

Wenn Sie
char ausCaptain[]="GeorgeBailey ";
StrTrim(ausCaptain," ");
Dies gibt ausCaptain als "GeorgeBailey" nicht "GeorgeBailey ".

Um meine Saiten von den beiden Seiten trimmen ich den Oldie verwenden, aber die gooody;) Es kann alles mit ascii trimmen weniger als ein Raum, was bedeutet, dass die Steuer Zeichen wird auch beschnitten werden!

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

Ich bin nur mit Code, weil das bisher geschrieben Code suboptimal scheint (und ich habe nicht die rep kommentieren noch.)

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() ist eine GNU-Erweiterung. Wenn Sie es nicht oder etwas Gleichwertiges haben, Ihre eigene Rolle. Zum Beispiel:

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

Hier verwende ich die dynamische Speicherzuweisung der Eingangskette an die Funktion trimStr zu trimmen. Erstens finden wir, wie viele nicht-leere Zeichen in der Eingabezeichenfolge vorhanden sind. Dann ordnen wir ein Zeichen-Array mit dieser Größe und das Aufpassen des Null-terminierten Charakter. Wenn wir diese Funktion zu nutzen, müssen wir in der Hauptfunktion der Speicher freizugeben.

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

Hier ist, wie ich es tun. Es schneidet die Zeichenfolge im Ort, also keine Sorgen über einen zurückgegebenen String Aufheben der Zuordnung oder den Zeiger auf ein zugeordneten String zu verlieren. Es kann nicht die kürzeste Antwort möglich sein, aber es sollte den meisten Lesern klar sein.

#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';
    }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top