Rimozione di spazi da una stringa in C?

Qual è il modo più semplice ed efficace per rimuovere spazi da una stringa in C?

I più semplici e più efficienti di solito non vanno insieme …

Ecco una ansible soluzione (non testata):

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

Ecco una versione molto compatta, ma completamente corretta:

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

E qui, solo per divertirmi, sono le versioni con codice del golf che non sono del tutto corrette, e fanno arrabbiare i commentatori.

Se puoi rischiare un comportamento indefinito e non avere mai stringhe vuote, puoi sbarazzarti del corpo:

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

Diamine, se per spazio intendi solo il carattere dello spazio:

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

Non usarlo in produzione 🙂

Come possiamo vedere dalle risposte pubblicate, questo non è sorprendentemente un compito banale. Di fronte a un compito come questo, sembrerebbe che molti programmatori scelgano di gettare il buon senso fuori dalla finestra, al fine di produrre il frammento più oscuro che possono eventualmente venire in mente.

Cose da considerare:

  • Dovrai fare una copia della stringa, con gli spazi rimossi. La modifica della stringa passata è una ctriggers pratica, potrebbe essere una stringa letterale. Inoltre, a volte ci sono dei vantaggi nel trattare le stringhe come oggetti immutabili .
  • Non si può presumere che la stringa di origine non sia vuota. Può contenere nient’altro che un singolo carattere di terminazione null.
  • Il buffer di destinazione può contenere qualsiasi spazzatura non inizializzata quando viene chiamata la funzione. Il controllo per la terminazione nulla non ha alcun senso.
  • La documentazione del codice sorgente dovrebbe indicare che il buffer di destinazione deve essere sufficientemente grande da contenere la stringa ritagliata. Il modo più semplice per farlo è renderlo grande come una stringa non tagliata.
  • Il buffer di destinazione deve contenere una stringa terminata null senza spazi quando la funzione viene eseguita.
  • Considerare se si desidera rimuovere tutti i caratteri dello spazio bianco o solo gli spazi ' ' .
  • La programmazione in C non è una competizione su chi può spremere quanti più operatori su una singola linea ansible. È piuttosto il contrario, un buon programma C contiene codice leggibile (sempre la qualità più importante) senza sacrificare l’efficienza del programma (un po ‘importante).
  • Per questo motivo, non ottieni punti bonus per hide l’inserimento della terminazione nulla della stringa di destinazione, lasciandola parte del codice di copia. Invece, rendere esplicito l’inserimento della terminazione nullo, per dimostrare che non sei riuscito a farlo correttamente per sbaglio.

Cosa farei:

 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 questo codice, la stringa di origine “str_untrimmed” non viene modificata, il che è garantito dall’uso della correttezza const corretta. Non si blocca se la stringa di origine non contiene nient’altro che una terminazione nulla. Sempre null termina la stringa di destinazione.

L’allocazione della memoria è lasciata al chiamante. L’algoritmo dovrebbe concentrarsi solo sul suo lavoro previsto. Rimuove tutti gli spazi bianchi.

Non ci sono trucchi sottili nel codice. Non tenta di spremere più operatori ansible su una singola riga. Farà un candidato molto povero per l’ IOCCC . Tuttavia produrrà più o meno lo stesso codice macchina delle versioni con uno strato più oscuro.

Quando si copia qualcosa, si può comunque ottimizzare un bit dichiarando come restrict entrambi i puntatori, che è un contratto tra il programmatore e il compilatore, in cui il programmatore garantisce che la destinazione e la fonte non sono lo stesso indirizzo (o piuttosto, che i dati punto a cui si accede solo attraverso quel puntatore stesso e non attraverso un altro puntatore). Ciò consente un’ottimizzazione più efficiente, poiché il compilatore può quindi copiare direttamente da una sorgente all’altra senza una memoria temporanea in mezzo.

In C, è ansible sostituire alcune stringhe sul posto, ad esempio una stringa restituita da strdup ():

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

Altre stringhe sono di sola lettura, ad esempio quelle dichiarate in codice. Dovresti copiare quelli in una nuova area di memoria allocata e riempire la copia saltando gli spazi:

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

Puoi capire perché la gente ha inventato altre lingue;)

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

Gli appunti;

  • Questo non gestisce Unicode.

se sei ancora interessato, questa funzione rimuove gli spazi dall’inizio della stringa e ho appena funzionato nel mio codice:

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

Il modo più semplice ed efficace per rimuovere spazi da una stringa è semplicemente rimuovere gli spazi dalla stringa letterale. Ad esempio, usa il tuo editor per “trovare e sostituire” "hello world" con "helloworld" , e presto!

Ok, so che non è quello che intendevi. Non tutte le stringhe derivano da stringhe letterali, giusto? Supponendo che questa stringa desideri che gli spazi rimossi non provengano da una stringa letterale, dobbiamo considerare l’origine e la destinazione della stringa … Dobbiamo considerare l’intero algoritmo, quale problema effettivo stai cercando di risolvere, in per suggerire i metodi più semplici e ottimali.

Forse la tua stringa proviene da un file (ad es. stdin ) ed è destinata a essere scritta in un altro file (es. stdout ). Se è così, mi chiedo perché mai debba diventare una stringa in primo luogo. Trattalo come se fosse un stream di personaggi, scartando gli spazi mentre li incontri …

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

Eliminando la necessità di memorizzare una stringa, non solo l’intero programma diventa molto, molto più breve, ma in teoria anche molto più efficiente.

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

Presumo che la stringa C sia in una memoria fissa, quindi se sostituisci gli spazi devi spostare tutti i caratteri.

Il più semplice sembra essere quello di creare una nuova stringa e iterare su quella originale e copiare solo caratteri non spaziali.

Questo è il più semplice che potessi pensare (TESTED) e funziona !!

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

Codice preso dalla libreria zString

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

Esempio di codice

  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 

Avere un llok al codice zString, potresti trovarlo utile https://github.com/fnoyanisi/zString

Mi sono imbattuto in una variazione di questa domanda in cui è necessario ridurre molti spazi in uno spazio “rappresentare” gli spazi.

Questa è la mia soluzione:

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

Spero che sia d’aiuto 🙂