Entfernen Sie Leerzeichen aus einer Zeichenfolge in C

Lesezeit: 9 Minuten

Benutzeravatar von Tyler Treat
Tyler behandeln

Was ist der einfachste und effizienteste Weg, um Leerzeichen aus einer Zeichenfolge in C zu entfernen?

  • Das Einfachste und das Effizienteste sind nicht unbedingt dasselbe

    – Allan H

    13. November 2009 um 0:09 Uhr

  • @JimFell Der Titel dieser Frage ist (war) sehr irreführend: Es geht nur darum, am Anfang Leerzeichen zu entfernen

    – Wolf

    12. August 2021 um 12:15 Uhr

Benutzeravatar von Aaron
Aaron

Das Einfachste und das Effizienteste passen normalerweise nicht zusammen…

Hier ist eine mögliche Lösung für die In-Place-Entfernung:

void remove_spaces(char* s) {
    char* d = s;
    do {
        while (*d == ' ') {
            ++d;
        }
    } while (*s++ = *d++);
}

  • Was passiert, wenn die Eingabequelle aus einem Zeichenfolgenliteral initialisiert wurde?

    – Feuer unterdrücken

    13. November 2009 um 1:11 Uhr

  • @Suppressingfire: Angenommen, du meinst RemoveSpaces("blah");und nicht char a[] = "blah"; RemoveSpaces(a);, dann undefiniertes Verhalten. Aber das ist nicht die Schuld dieses Codes. Es wird nicht empfohlen, eine schreibgeschützte Zeichenfolge an eine Funktion zu übergeben, die dokumentiert ist, um die an sie übergebene Zeichenfolge zu ändern (z. B. durch Entfernen von Leerzeichen) 😉

    – Steve Jessop

    13. November 2009 um 1:25 Uhr

  • Ich denke, Sie sollten *i = ‘\0’ tun; schlussendlich.

    – Nick Louloudakis

    12. November 2013 um 14:14 Uhr

  • * ich = 0 und *i = ‘\0’ ist dasselbe 🙂

    – Uxi

    31. März 2015 um 14:31 Uhr

  • Wie… Wie funktioniert das? Ich bin neu in C und Zeigern, daher wäre eine exemplarische Vorgehensweise zu dem, was passiert, sehr willkommen

    – starscream_disco_party

    14. Februar 2016 um 20:57 Uhr

Benutzeravatar von Kornel
Kornel

Hier ist eine sehr kompakte, aber völlig korrekte Version:

do while(isspace(*s)) s++; while(*d++ = *s++);

Und hier, nur zu meiner Unterhaltung, sind Code-Golf-Versionen, die nicht ganz korrekt sind und die Kommentatoren verärgern.

Wenn Sie ein undefiniertes Verhalten riskieren können und niemals leere Zeichenfolgen haben, können Sie den Körper loswerden:

while(*(d+=!isspace(*s++)) = *s);

Verdammt, wenn Sie mit Leerzeichen nur ein Leerzeichen meinen:

while(*(d+=*s++!=' ')=*s);

Verwenden Sie das nicht in der Produktion 🙂

  • Interessant, die ersten beiden funktionieren auf meiner Maschine. Aber ich denke, all diese sind undefiniert, da die Verwendung von s++ und *s in einer Anweisung zu undefiniertem Verhalten führt?

    – Andomar

    13. November 2009 um 0:54 Uhr

  • Stellen Sie sicher, dass Sie beim Dereferenzieren nicht über das Ende der Zeichenfolge hinausgehen.

    – Casey

    13. November 2009 um 0:59 Uhr

  • @Andomar: Der erste ist völlig sicher und gesund. Die letzten beiden sind in der Tat lückenhaft (getestet in GCC4.2).

    – Körnel

    13. November 2009 um 1:50 Uhr

  • Es “sound” zu nennen, ist vielleicht etwas zu höflich. Alle 3 Versionen sind komplett unlesbar, ohne Performancegewinn. Apple stimmt zu dass Klammern unnötig sind. Ich meine, was sind viele Millionen Dollar an Verlusten und all die Programmierer der Welt, die Sie auslachen, verglichen mit der reinen Qual, die mit dem Schreiben von Klammern verbunden ist?

    – Ludin

    21. Mai 2015 um 11:35 Uhr


  • Warum ist es notwendig, undefiniertes Verhalten zu riskieren, wenn Sie dieses Risiko mit dem Komma-Operator und a lösen könnten for Schleife?

    – autistisch

    24. Mai 2015 um 0:41 Uhr

Benutzeravatar von Lundin
Lundin

Wie wir den geposteten Antworten entnehmen können, ist dies überraschenderweise keine triviale Aufgabe. Wenn sie mit einer Aufgabe wie dieser konfrontiert werden, scheinen viele Programmierer ihren gesunden Menschenverstand über Bord zu werfen, um den obskursten Schnipsel zu produzieren, der ihnen überhaupt einfallen kann.

Dinge, die man beachten muss:

  • Sie möchten eine Kopie der Zeichenfolge erstellen, wobei Leerzeichen entfernt werden. Das Ändern der übergebenen Zeichenfolge ist eine schlechte Vorgehensweise, es kann sich um ein Zeichenfolgenliteral handeln. Außerdem hat es manchmal Vorteile, Saiten so zu behandeln unveränderliche Objekte.
  • Sie können nicht davon ausgehen, dass die Quellzeichenfolge nicht leer ist. Es darf nur ein einzelnes Null-Terminierungszeichen enthalten.
  • Der Zielpuffer kann nicht initialisierten Müll enthalten, wenn die Funktion aufgerufen wird. Es macht keinen Sinn, es auf Nullterminierung zu prüfen.
  • Die Quellcodedokumentation sollte angeben, dass der Zielpuffer groß genug sein muss, um die gekürzte Zeichenfolge aufzunehmen. Der einfachste Weg, dies zu tun, besteht darin, ihn so groß wie die ungetrimmte Saite zu machen.
  • Der Zielpuffer muss eine nullterminierte Zeichenfolge ohne Leerzeichen enthalten, wenn die Funktion ausgeführt wird.
  • Überlegen Sie, ob Sie alle Leerzeichen oder nur Leerzeichen entfernen möchten ' '.
  • Die C-Programmierung ist kein Wettbewerb darüber, wer so viele Operatoren wie möglich in eine einzige Zeile quetschen kann. Es ist eher das Gegenteil, ein gutes C-Programm enthält lesbaren Code (immer die allerwichtigste Qualität), ohne die Programmeffizienz (ziemlich wichtig) zu opfern.
  • Aus diesem Grund erhalten Sie keine Bonuspunkte dafür, das Einfügen der Nullterminierung des Zielstrings zu verbergen, indem Sie es Teil des Kopiercodes sein lassen. Machen Sie stattdessen das Einfügen der Nullterminierung explizit, um zu zeigen, dass Sie es nicht nur aus Versehen geschafft haben, es richtig zu machen.

Was ich tun würde:

void remove_spaces (char* restrict str_trimmed, const char* restrict str_untrimmed)
{
  while (*str_untrimmed != '\0')
  {
    if(!isspace(*str_untrimmed))
    {
      *str_trimmed = *str_untrimmed;
      str_trimmed++;
    }
    str_untrimmed++;
  }
  *str_trimmed = '\0';
}

In diesem Code bleibt die Quellzeichenfolge „str_untrimmed“ unberührt, was durch die Verwendung der richtigen const-Korrektheit garantiert wird. Es stürzt nicht ab, wenn die Quellzeichenfolge nichts als eine Nullterminierung enthält. Es beendet die Zielzeichenfolge immer mit null.

Die Speicherzuordnung bleibt dem Aufrufer überlassen. Der Algorithmus sollte sich nur darauf konzentrieren, seine beabsichtigte Arbeit zu erledigen. Es entfernt alle Leerzeichen.

Es gibt keine subtilen Tricks im Code. Es wird nicht versucht, so viele Operatoren wie möglich in eine einzige Zeile zu quetschen. Es wird einen sehr schlechten Kandidaten für die abgeben IOCCC. Dennoch liefert es so ziemlich den gleichen Maschinencode wie die obskureren Einzeiler-Versionen.

Wenn Sie etwas kopieren, können Sie jedoch etwas optimieren, indem Sie beide Zeiger als deklarieren restrict, bei dem es sich um einen Vertrag zwischen dem Programmierer und dem Compiler handelt, bei dem der Programmierer garantiert, dass das Ziel und die Quelle nicht dieselbe Adresse sind. Dies ermöglicht eine effizientere Optimierung, da der Compiler dann ohne Zwischenspeicher direkt von der Quelle zum Ziel kopieren kann.

  • Warum die verwenden restrict Stichwort? Es gibt keinen Grund, warum Sie nicht denselben Zeiger als Quelle und Ziel übergeben können sollten, und Ihr Code unterstützt dies.

    – chqrlie

    12. Oktober 2016 um 21:20 Uhr

  • @chqrlie Es könnte sicherlich auf Kosten von langsamerem Code im generischen Anwendungsfall entfernt werden. Ich glaube nicht, dass ich diesen Code bewertet habe, aber ich vermute, dass es keinen großen Unterschied machen sollte.

    – Ludin

    13. Oktober 2016 um 6:40 Uhr

  • Dies ist die vernünftigste Antwort, die ich gesehen habe. Es ist klar, prägnant und für einen Anfänger gut verständlich! Vielen Dank.

    – PageMaker

    3. Februar 2021 um 18:24 Uhr

  • Ich würde ersetzen str_untrimmed durch scattered und str_trimmed durch condensed.

    – Wolf

    12. August 2021 um 12:47 Uhr

  • @Wolf Gut für dich. Hören Sie jetzt bitte auf, die Beiträge anderer mit geringfügigen überflüssigen Änderungen zu zerstören oder den Codierungsstil an Ihre persönlichen Vorlieben anzupassen. Sie haben anscheinend einen zu hohen Ruf, um Änderungen überprüfen zu lassen, oder Sie würden eine Änderungssperre erhalten.

    – Ludin

    12. August 2021 um 14:38 Uhr

Benutzeravatar von Andomar
Andomar

In C können Sie einige Strings direkt ersetzen, zum Beispiel einen String, der von strdup() zurückgegeben wird:

char *str = strdup(" a b c ");

char *write = str, *read = str;
do {
   if (*read != ' ')
       *write++ = *read;
} while (*read++);

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

Andere Zeichenfolgen sind schreibgeschützt, z. B. die im Code deklarierten. Sie müssten diese in einen neu zugewiesenen Speicherbereich kopieren und die Kopie füllen, indem Sie die Leerzeichen überspringen:

char *oldstr = " a b c ";

char *newstr = malloc(strlen(oldstr)+1);
char *np = newstr, *op = oldstr;
do {
   if (*op != ' ')
       *np++ = *op;
} while (*op++);

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

Sie können sehen, warum Menschen andere Sprachen erfunden haben;)

Quarks Benutzeravatar
Quark

#include <ctype>

char * remove_spaces(char * source, char * target)
{
     while(*source++ && *target)
     {
        if (!isspace(*source)) 
             *target++ = *source;
     }
     return target;
}

Anmerkungen;

  • Dies behandelt Unicode nicht.

  • Wird dadurch nicht das erste Zeichen übersprungen?

    – Aaron

    13. November 2009 um 0:17 Uhr

  • Sie sollten den übergebenen Wert umwandeln isspace zu unsigned charda diese Funktion so definiert ist, dass sie einen Wert im Bereich von akzeptiert unsigned charoder EOF.

    – Café

    13. November 2009 um 0:22 Uhr

  • Es entfernt immer noch das erste Zeichen und schlägt fehl, wenn es mit aufgerufen wird target contating ‘\0’ in seinem ersten Element (ich verstehe nicht, was der Zweck ist, seinen Inhalt zu überprüfen). Wechseln while(*source++ && *target) {...} zu do {...} while(*source++); scheint gut zu funktionieren.

    – mMontu

    24. Mai 2012 um 14:53 Uhr

  • Meinten Sie ctype.h?

    – Spikatrix

    20. Mai 2015 um 14:29 Uhr

  • 1) Ein anfängliches Leerzeichen kann nicht entfernt werden source. 2) Fügt niemals ein abschließendes Nullzeichen an an target wenn source == "". 3) Abhängig vom Wert in target[0].

    – chux – Wiedereinsetzung von Monica

    20. Mai 2015 um 20:51 Uhr

Benutzeravatar von Alfredo
Alfredo

Wenn Sie immer noch interessiert sind, entfernt diese Funktion Leerzeichen am Anfang der Zeichenfolge, und ich hatte es gerade in meinem Code zum Laufen gebracht:

void removeSpaces(char *str1)  
{
    char *str2; 
    str2=str1;  
    while (*str2==' ') str2++;  
    if (str2!=str1) memmove(str1,str2,strlen(str2)+1);  
}

  • Wird dadurch nicht das erste Zeichen übersprungen?

    – Aaron

    13. November 2009 um 0:17 Uhr

  • Sie sollten den übergebenen Wert umwandeln isspace zu unsigned charda diese Funktion so definiert ist, dass sie einen Wert im Bereich von akzeptiert unsigned charoder EOF.

    – Café

    13. November 2009 um 0:22 Uhr

  • Es entfernt immer noch das erste Zeichen und schlägt fehl, wenn es mit aufgerufen wird target contating ‘\0’ in seinem ersten Element (ich verstehe nicht, was der Zweck ist, seinen Inhalt zu überprüfen). Wechseln while(*source++ && *target) {...} zu do {...} while(*source++); scheint gut zu funktionieren.

    – mMontu

    24. Mai 2012 um 14:53 Uhr

  • Meinten Sie ctype.h?

    – Spikatrix

    20. Mai 2015 um 14:29 Uhr

  • 1) Ein anfängliches Leerzeichen kann nicht entfernt werden source. 2) Fügt niemals ein abschließendes Nullzeichen an an target wenn source == "". 3) Abhängig vom Wert in target[0].

    – chux – Wiedereinsetzung von Monica

    20. Mai 2015 um 20:51 Uhr

Benutzeravatar von Praveen
Praveen

#include<stdio.h>
#include<string.h>
main()
{
  int i=0,n;
  int j=0;
  char str[]="        Nar ayan singh              ";
  char *ptr,*ptr1;
  printf("sizeof str:%ld\n",strlen(str));
  while(str[i]==' ')
   {
     memcpy (str,str+1,strlen(str)+1);
   }
  printf("sizeof str:%ld\n",strlen(str));
  n=strlen(str);
  while(str[n]==' ' || str[n]=='\0')
    n--;
  str[n+1]='\0';
  printf("str:%s ",str);
  printf("sizeof str:%ld\n",strlen(str));
}

  • strlen kehrt zurück size_t. Also verwenden %zunicht %ld. Und verwenden int main() zusammen mit return 0;

    – Spikatrix

    20. Mai 2015 um 14:31 Uhr

  • Zusätzlich, memcpy ist zum Kopieren überlappender Speicherbereiche ungeeignet. Verwenden memmove stattdessen.

    – autistisch

    21. Mai 2015 um 9:52 Uhr

1411300cookie-checkEntfernen Sie Leerzeichen aus einer Zeichenfolge in C

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy