it-swarm.com.de

Wie schneide ich führende/nachlaufende Leerzeichen auf herkömmliche Weise?

Gibt es eine saubere, vorzugsweise Standardmethode, um führende und nachgestellte Leerzeichen von einer Zeichenfolge in C zu trimmen? Ich würde meinen eigenen würfeln, aber ich würde denken, dass dies ein allgemeines Problem mit einer ebenso üblichen Lösung ist.

156
coledot

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, können Sie grundsätzlich dieselbe 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;
}
148
Adam Rosenfield

Hier ist eine, die die Zeichenkette in die erste Position Ihres Puffers verschiebt. Möglicherweise möchten Sie dieses Verhalten, wenn Sie die Zeichenfolge dynamisch zugewiesen haben, können Sie sie jedoch weiterhin für denselben Zeiger freigeben, den 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 auf Korrektheit:

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

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

31
indiv

Meine Lösung. String muss änderbar sein. Der Vorteil gegenüber einigen anderen Lösungen besteht darin, dass der Nicht-Leerzeichen-Teil an den Anfang verschoben wird, sodass Sie den alten Zeiger verwenden können, falls Sie ihn später freigeben müssen.

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 der Zeichenfolge mit strndup (), anstatt sie an Ort und Stelle zu bearbeiten. strndup () erfordert _GNU_SOURCE, daher müssen Sie möglicherweise mit malloc () und strncpy () ein eigenes strndup () erstellen.

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

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

    return strndup(s, l);
}
20
jkramer

Hier ist meine C-Mini-Bibliothek zum Trimmen von Links, Rechts, beiden, allen, an Ort und Stelle und getrennt sowie zum Trimmen eines Satzes angegebener Zeichen (oder standardmäßig Leerzeichen).

Inhalt von 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 von 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 macht alles. Es wird angepasst, wenn src == dst , andernfalls funktioniert es wie die Routinen strcpy. Es schneidet eine Reihe von Zeichen ab, die in der Zeichenfolge als Trennzeichen angegeben sind, oder Leerzeichen, wenn null. Es schneidet links, rechts, beide und alle (wie tr). Es steckt nicht viel dahinter und es wird nur einmal über die Zeichenfolge iteriert. Einige Leute könnten sich darüber beschweren, dass das Trimmen von rechts nach links beginnt. (Auf die eine oder andere Weise müssen Sie zum Ende der Zeichenkette gelangen, damit Sie die Arbeit genauso gut erledigen können, wie Sie es tun.) Es kann Argumente geben, die sich auf das Pipelining und die Cache-Größen beziehen, und solche - wer weiß . Da die Lösung von links nach rechts funktioniert und nur einmal iteriert, kann sie auch für Streams erweitert werden. Einschränkungen: Es funktioniert nicht mit nicode Strings.

10
Shoots the Moon

Hier ist mein Versuch einer einfachen, aber korrekten In-Place-Trim-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.
}
7
Swiss

Spät zur Party

Eigenschaften:
1. Schneiden Sie den Anfang wie in einer Reihe anderer Antworten schnell ab.
2. Wenn Sie bis zum Ende gegangen sind, schneiden Sie die rechte mit nur einem Test pro Schleife ab. Wie @ jfm3, funktioniert aber für eine Leerzeichenfolge.
3. Um undefiniertes Verhalten zu vermeiden, wenn char eine signierte char ist, wandeln Sie *s in unsigned char

Character handling "In allen Fällen ist das Argument eine int, deren Wert als unsigned char darstellbar sein soll oder dem Wert des Makros EOF entsprechen soll. 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 kommentierte das obige verschiebt die getrimmte Zeichenfolge nicht. Dazu ....

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

Eine andere, mit einer Zeile, die den richtigen Job macht:

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

Ich mochte die meisten dieser Antworten nicht, weil sie eine oder mehrere der folgenden Aussagen machten ...

  1. Hat einen anderen Zeiger in der Zeichenfolge des ursprünglichen Zeigers zurückgegeben (eine Art Schmerz, um zwei verschiedene Zeiger auf dasselbe zu jonglieren).
  2. Hat Dinge wie strlen () , die die gesamte Zeichenfolge zuvor durchlaufen, unentgeltlich genutzt.
  3. Verwendete nicht-portable OS-spezifische Lib-Funktionen.
  4. Zurück gescannt.
  5. Verwendeter Vergleich mit '' anstelle von isspace () , damit TAB/CR/LF erhalten bleibt.
  6. Verschwendeter Speicher mit großen statischen Puffern.
  7. Verschwendete Zyklen mit teuren Funktionen 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';
}
3
Jason Stewart

Hier ist eine Lösung ähnlich der @ adam-rosenfields-Modifikationsroutine vor Ort, ohne jedoch unnötig auf strlen () zurückzugreifen. Wie @jkramer wird die Zeichenfolge innerhalb des Puffers linksbündig eingestellt, sodass Sie denselben Zeiger freigeben können. Für große Zeichenfolgen nicht optimal, da Memmove nicht verwendet wird. Enthält die ++/- Operatoren, die @ jfm3 erwähnt. FCTX -basierte Komponententests 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();
3
Rhys Ulerich

Sehr spät zur Party ...

Vorwärts-Scan-Lösung mit einem Durchlauf ohne Rückverfolgung. Jedes Zeichen in der Quellzeichenfolge wird genau getestet einmal zweimal. (Es sollte also schneller als die meisten anderen Lösungen sein, insbesondere wenn der Quellstring viele Leerzeichen enthält.)

Dazu gehören zwei Lösungen, eine zum Kopieren und Trimmen einer Quellzeichenfolge in eine andere Zielzeichenfolge und die andere zum Trimmen der Quellzeichenfolge. Beide Funktionen verwenden den gleichen Code.

Die (modifizierbare) 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);
}
2
David R Tribble

Die einfachste Möglichkeit, Leerzeichen in einer Zeichenfolge zu überspringen, ist

#include <stdio.h>

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

Ok, das ist meine Meinung zu der Frage. Ich glaube, es ist die prägnanteste Lösung, die den String an Ort und Stelle modifiziert (free wird funktionieren) und UB vermeiden. Für kleine Saiten ist dies wahrscheinlich schneller als eine Lösung, die memmove beinhaltet.

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

Ich bin mir nicht sicher, was Sie als "schmerzlos" betrachten.

C-Saiten sind ziemlich schmerzhaft. Wir können die erste Nicht-Whitespace-Charakterposition trivial finden:

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

Wir können die letzte Nicht-Whitespace-Charakterposition mit zwei ähnlichen trivialen Bewegungen ermitteln:

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

(Ich habe Ihnen die Schmerzen erspart, die *- und ++-Operatoren gleichzeitig zu verwenden.)

Die Frage ist nun, was machen Sie damit? Der zur Verfügung stehende Datentyp ist nicht wirklich ein robuster abstrakter String, über den man leicht nachdenken kann, sondern eher kaum mehr als ein Array von Speicherbytes. Da es keinen robusten Datentyp gibt, ist es nicht möglich, eine Funktion zu schreiben, die dieselbe Funktion wie die Funktion chomp von PHperytonby ausführt. Was würde eine solche Funktion in C zurückgeben?

1
jfm3

Nur um dieses Wachstum aufrecht zu erhalten, eine weitere Option mit einer veränderbaren Zeichenfolge:

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);
}
1
wallek876
#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;
}
1
#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 Leerzeichen zu trimmen.

  • Führen Sie eine erste Schleife aus, um das letzte Byte auf Leerzeichen zu prüfen und die Längenvariable zu reduzieren
  • Führen Sie eine zweite Schleife aus, um vom ersten Byte auf Leerzeichen zu prüfen und die Längenvariable und den Inkrementzeichenzeiger zu reduzieren.
  • Wenn die Längenvariable schließlich mehr als 0 ist, erstellen Sie mit strndup einen neuen Zeichenfolgenpuffer, indem Sie Leerzeichen ausschließen.
1
rashok

Ich weiß, dass es viele Antworten gibt, aber ich poste hier meine Antwort, 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;
}
1
Ekeyme Mo

s war so extrem hilfreich, ich wollte sagen, ich war froh, dass dieser Beitrag verfügbar war, und um zu zeigen, was ich mit den Beispielen tun konnte. Ich musste eine größere Zeichenkette mit einem Token versehen und dann die Teilzeichenfolge (n) nehmen und die letzte finden - so konnte ich eine Newline aus dem Aufruf von fgets () entfernen und auch den Whitespace vor dem Token entfernen - so konnte ich Einfach mit einem statischen String vergleichen. Das erste Beispiel in dem obigen Beitrag hat mich dort hingebracht, also danke. So habe ich die Codebeispiele und die Ausgabe verwendet, die ich bekommen 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;

}

Ausgabe

Datei existiert.

String: DBS State: DBS Startup - DBS-Konfiguration wird initialisiert

DBS State

DBS-Start

DBS-Start

DBS-Konfiguration wird initialisiert

DBS-Konfiguration wird initialisiert

Strings sind gleich.

Tokenisierung erledigt.

1
Diana

Wenn Sie glib verwenden, können Sie g_strstrip verwenden.

1
sleepycal

Verwenden Sie eine string Bibliothek , zum Beispiel:

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

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

... wie Sie sagen, dies ist ein "allgemeines" Problem, ja, Sie müssen ein # include enthalten oder so und es ist nicht in libc enthalten, aber Sie müssen nicht Ihren eigenen Hackjob erfinden, der zufällige Zeiger speichert und size_t nur so führt Pufferüberläufe.

1
James Antill

Die meisten Antworten haben bisher eine der folgenden Möglichkeiten:

  1. Gehen Sie am Ende der Zeichenfolge zurück (d. H. Suchen Sie das Ende der Zeichenfolge und suchen Sie dann rückwärts, bis ein Zeichen ohne Leerzeichen gefunden wird) oder
  2. Rufen Sie zuerst strlen() auf, und machen Sie einen zweiten Durchlauf durch die gesamte Zeichenfolge.

Diese Version führt nur einen Durchlauf durch und führt keine Rückverfolgung durch. Daher ist die Leistung möglicherweise besser als bei den anderen, jedoch nur, wenn häufig hunderte von Leerzeichen vorhanden sind (was bei der Ausgabe einer SQL-Abfrage nicht ungewöhnlich ist). 

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
finnw

Durch diese Funktionen wird der ursprüngliche Puffer geändert. Wenn der dynamische Zeiger.

#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
Telc

So mache ich es. Die Zeichenfolge wird an Ort und Stelle gekürzt, sodass Sie sich keine Sorgen machen müssen, ob eine zurückgegebene Zeichenfolge freigegeben oder der Zeiger auf eine zugewiesene Zeichenfolge verloren geht. Es ist möglicherweise nicht die kürzeste mögliche Antwort, sollte aber 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';
    }
}
0
Isaac To

Um meine Saiten von beiden Seiten zu trimmen, verwende ich den Oldie außer dem Gooody.

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;
}
char* strtrim(char* const str)
{
    if (str != nullptr)
    {
        char const* begin{ str };
        while (std::isspace(*begin))
        {
            ++begin;
        }

        auto end{ begin };
        auto scout{ begin };
        while (*scout != '\0')
        {
            if (!std::isspace(*scout++))
            {
                end = scout;
            }
        }

        auto /* std::ptrdiff_t */ const length{ end - begin };
        if (begin != str)
        {
            std::memmove(str, begin, length);
        }

        str[length] = '\0';
    }

    return str;
}
0
Mitch Laber

Hier verwende ich die dynamische Speicherzuordnung, um die Eingabezeichenfolge auf die Funktion trimStr zu trimmen. Zuerst ermitteln wir, wie viele nicht leere Zeichen in der Eingabezeichenfolge vorhanden sind. Dann weisen wir ein Zeichenarray mit dieser Größe zu und kümmern uns um das mit Null abgeschlossene Zeichen. Wenn wir diese Funktion verwenden, müssen wir den Speicher innerhalb der Hauptfunktion freigeben. 

#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
saeed_falahat

Ich füge nur Code hinzu, da der bisher veröffentlichte Code suboptimal erscheint (und ich habe noch nicht den Vertreter, der das kommentiert.)

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 Erweiterung von GNU. Wenn Sie es nicht haben oder etwas Äquivalentes, rollen Sie Ihre eigene. Zum Beispiel:

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

Persönlich würde ich meine eigene rollen. Sie können strtok verwenden, aber Sie müssen darauf achten (insbesondere, wenn Sie führende Zeichen entfernen), dass Sie wissen, welcher Speicher was ist.

Leerzeichen zu entfernen ist einfach und ziemlich sicher, da Sie einfach eine 0 über das letzte Leerzeichen setzen können und vom Ende zurückzählen. Führende Räume loswerden bedeutet, Dinge zu bewegen. Wenn Sie es vor Ort tun möchten (wahrscheinlich vernünftig), können Sie einfach alles um einen Charakter zurück verschieben, bis es keinen führenden Platz gibt. Oder, um effizienter zu sein, können Sie den Index des ersten Nicht-Leerzeichens finden und alles um diese Zahl zurückschieben. Oder Sie könnten einfach einen Zeiger auf das erste Zeichen ohne Leerzeichen verwenden (aber Sie müssen auf dieselbe Weise vorsichtig sein wie mit strtok).

0
Ben

Ein bisschen zu spät zum Spiel, aber ich werde meine Routinen in den Kampf werfen. Sie sind wahrscheinlich nicht die absolut effizientesten, aber ich glaube, dass sie korrekt sind und einfach sind (mit rtrim(), das den Komplexitätsumschlag vorantreibt):

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

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

    Michael Burr
    [email protected]
    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
Michael Burr

Dies ist die kürzeste mögliche Implementierung, die mir einfällt:

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
}
0
Michał Gawlas

Was halten Sie von der Verwendung der in header Shlwapi.h definierten StrTrim-Funktion? Es ist ziemlich einfach, es selbst zu definieren.
Details finden Sie unter:
http://msdn.Microsoft.com/en-us/library/windows/desktop/bb773454 (v = vs.85) .aspx

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

0
Carthi