Entfernen von Leerzeichen aus einer Zeichenfolge in C?

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

Einfachste und effizienteste gehen normalerweise nicht zusammen …

Hier ist eine mögliche Lösung (ungetestet):

void RemoveSpaces(char* source) { char* i = source; char* j = source; while(*j != 0) { *i = *j++; if(*i != ' ') i++; } *i = 0; } 

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

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

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

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

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

Hey, wenn du mit Space meinst du nur Space Charakter:

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

Benutze das nicht in der Produktion 🙂

Wie wir aus den Antworten sehen können, ist dies überraschenderweise keine triviale Aufgabe. Bei einer solchen Aufgabe scheinen viele Programmierer den gesunden Menschenverstand aus dem Fenster zu casting, um den dunkelsten Ausschnitt zu erzeugen, den sie möglicherweise hervorbringen können.

Dinge, die man beachten muss:

  • Sie möchten eine Kopie der Zeichenfolge mit entfernten Leerzeichen erstellen. Das Ändern der übergebenen Zeichenfolge ist eine schlechte Vorgehensweise, möglicherweise ein Zeichenfolgenliteral. Manchmal gibt es auch Vorteile, Strings als unveränderliche Objekte zu behandeln .
  • Sie können nicht davon ausgehen, dass die Quellzeichenfolge nicht leer ist. Es darf nur ein einziges Null-Beendigungszeichen enthalten.
  • Der Zielpuffer kann beim Aufruf der function nicht initialisierten Müll enthalten. Es auf Null zu prüfen macht keinen Sinn.
  • Quellcodedokumentation sollte angeben, dass der Zielpuffer groß genug sein muss, um die beschnittene Zeichenfolge zu enthalten. Der einfachste Weg ist, es so groß wie die unbeschnittene Saite zu machen.
  • Der Zielpuffer muss eine nullterminierte Zeichenfolge ohne Leerzeichen enthalten, wenn die function beendet ist.
  • Überlegen Sie, ob Sie alle Leerzeichen oder nur Leerzeichen entfernen möchten.
  • C-Programmierung ist kein Wettbewerb darüber, wer so viele Operatoren auf einer einzigen Linie wie möglich zusammenpressen kann. Es ist eher das Gegenteil, ein gutes C-Programm enthält lesbaren Code (immer die wichtigste Qualität), ohne Programm-Effizienz zu opfern (etwas wichtig).
  • Aus diesem Grund erhalten Sie keine Bonuspunkte, um die Einfügung der Nullbeendigung der Zielzeichenfolge zu verbergen, indem Sie sie Teil des Kopiercodes werden lassen. Machen Sie stattdessen die Null-Terminierungseinfügung explizit, um zu zeigen, dass Sie es nicht gerade zufällig geschafft haben.

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 wird die Quell-Zeichenkette “str_untrimmed” nicht verändert, was durch eine korrekte const-Korrektheit gewährleistet ist. Es stürzt nicht ab, wenn die Quellzeichenfolge nichts als eine Null-Beendigung enthält. Immer null beendet die Zielzeichenfolge.

Die Speicherzuordnung bleibt dem Aufrufer überlassen. Der Algorithmus sollte sich nur auf die beabsichtigte Arbeit konzentrieren. Es entfernt alle weißen Bereiche.

Es gibt keine subtilen Tricks im Code. Es versucht nicht, so viele Operatoren wie möglich in einer einzigen Zeile einzuquetschen. Es wird ein sehr schlechter Kandidat für das IOCCC sein . Aber es wird fast den gleichen Maschinencode ergeben wie die obskureren Einliner-Versionen.

Wenn Sie etwas kopieren, können Sie jedoch ein wenig optimieren, indem Sie beide pointers als restrict deklarieren, was ein Vertrag zwischen dem Programmierer und dem Compiler ist, bei dem der Programmierer garantiert, dass das Ziel und die Quelle nicht die gleiche Adresse sind (oder vielmehr die Daten) Der Zugriffspunkt wird nur über diesen pointers und nicht über einen anderen pointers aufgerufen. Dies ermöglicht eine effizientere Optimierung, da der Compiler dann direkt von der Quelle zum Ziel kopieren kann, ohne dazwischen einen temporären Speicher zu haben.

In C können Sie einige Zeichenfolgen ersetzen, z. B. eine Zeichenfolge, die von strdup () zurückgegeben wird:

 char *str = strdup(" abc "); char *write = str, *read = str; do { if (*read != ' ') *write++ = *read; } while (*read++); printf("%s\n", str); 

Andere Zeichenfolgen sind schreibgeschützt, beispielsweise solche, die in Code deklariert wurden. Sie müssten diese in einen neu zugewiesenen Speicherbereich kopieren und die Kopie füllen, indem Sie die Leerzeichen überspringen:

 char *oldstr = " abc "; 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;)

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

Anmerkungen;

  • Dies behandelt nicht Unicode.

Wenn Sie noch interessiert sind, entfernt diese function Leerzeichen vom Anfang der Zeichenfolge, und ich habe es gerade in meinem Code funktioniert:

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

Die einfachste und effizienteste Möglichkeit, Leerzeichen aus einer Zeichenfolge zu entfernen, besteht darin, die Leerzeichen einfach aus dem Zeichenfolgenliteral zu entfernen. Verwenden Sie beispielsweise Ihren Editor, um "hello world" mit "helloworld" zu finden und zu ersetzen, und presto!

Okay, ich weiß, dass du das nicht meintest. Nicht alle Zeichenfolgen stammen aus Zeichenfolgenliteralen, richtig? Angenommen, diese Zeichenfolge, aus der Leerzeichen entfernt werden sollen, stammt nicht aus einem Zeichenfolgenliteral, sondern müssen die Quelle und das Ziel der Zeichenfolge berücksichtigen … Wir müssen Ihren gesamten Algorithmus berücksichtigen, welches eigentliche Problem Sie lösen möchten um die einfachsten und optimalsten Methoden vorzuschlagen.

Vielleicht kommt Ihre Zeichenkette aus einer Datei (zB stdin ) und muss in eine andere Datei geschrieben werden (zB stdout ). Wenn das der Fall ist, würde ich mich fragen, warum es überhaupt jemals zu einer Zeichenkette werden muss. Behandle es einfach so, als ob es ein Strom von Charakteren wäre, und verwerfe die Räume, wenn du auf sie stößt …

 #include  int main(void) { for (;;) { int c = getchar(); if (c == EOF) { break; } if (c == ' ') { continue; } putchar(c); } } 

Indem die Notwendigkeit der Speicherung eines Strings beseitigt wird, wird nicht nur das gesamte Programm viel, viel kürzer, sondern theoretisch auch viel effizienter.

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

Ich nehme an, die C-Zeichenfolge befindet sich in einem festen Speicher. Wenn Sie Leerzeichen ersetzen, müssen Sie alle Zeichen verschieben.

Am einfachsten scheint es zu sein, eine neue Zeichenfolge zu erstellen und über die ursprüngliche zu iterieren und nur Nicht-Leerzeichen-Zeichen zu kopieren.

Das ist das Einfachste, was ich mir vorstellen kann (getestet) und es funktioniert !!

 char message[50]; fgets(message, 50, stdin); for( i = 0, j = 0; i < strlen(message); i++){ message[ij] = message[i]; if(message[i] == ' ') j++; } message[i] = '\0'; 

Code aus der zString-Bibliothek

 /* search for character 's' */ int zstring_search_chr(char *token,char s){ if (!token || s=='\0') return 0; for (;*token; token++) if (*token == s) return 1; return 0; } char *zstring_remove_chr(char *str,const char *bad) { char *src = str , *dst = str; /* validate input */ if (!(str && bad)) return NULL; while(*src) if(zstring_search_chr(bad,*src)) src++; else *dst++ = *src++; /* assign first, then incement */ *dst='\0'; return str; } 

Codebeispiel

  Exmaple Usage char s[]="this is a trial string to test the function."; char *d=" ."; printf("%s\n",zstring_remove_chr(s,d)); Example Output thisisatrialstringtotestthefunction 

Haben Sie einen llok im zString-Code, können Sie es nützlich https://github.com/fnoyanisi/zString finden

Ich bin auf eine Variation dieser Frage gestoßen, bei der man multiplizierte Räume in einem Raum reduzieren muss, um die Räume “darzustellen”.

Das ist meine Lösung:

 char str[] = "Put Your string Here....."; int copyFrom = 0, copyTo = 0; printf("Start String %s\n", str); while (str[copyTo] != 0) { if (str[copyFrom] == ' ') { str[copyTo] = str[copyFrom]; copyFrom++; copyTo++; while ((str[copyFrom] == ' ') && (str[copyFrom] !='\0')) { copyFrom++; } } str[copyTo] = str[copyFrom]; if (str[copyTo] != '\0') { copyFrom++; copyTo++; } } printf("Final String %s\n", str); 

Ich hoffe es hilft 🙂