web-dev-qa-db-fra.com

Supprimer des espaces d'une chaîne en C?

Quel est le moyen le plus simple et le plus efficace de supprimer des espaces dans une chaîne en C?

41
Tyler Treat

Le plus simple et le plus efficace ne vont généralement pas ensemble ...

Voici une solution possible (non testée):

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

Voici une version très compacte, mais tout à fait correcte:

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

Et voici, juste pour mon amusement, des versions codées en golf qui ne sont pas tout à fait correctes et qui dérangent les commentateurs.

Si vous pouvez risquer un comportement indéfini et ne jamais avoir de chaîne vide, vous pouvez vous débarrasser du corps:

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

Heck, si par espace vous entendez simplement le caractère d'espace:

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

N'utilisez pas ça en production :)

17
Kornel

Comme nous pouvons le constater à partir des réponses, ceci n’est pas une tâche anodine. Face à une telle tâche, il semblerait que de nombreux programmeurs choisissent de jeter le bon sens par la fenêtre, afin de produire l'extrait le plus obscur qu'ils puissent éventuellement trouver.

Choses à considérer:

  • Vous voudrez faire une copie de la chaîne en supprimant les espaces. La modification de la chaîne passée est une mauvaise pratique, il peut s'agir d'un littéral de chaîne. En outre, il est parfois avantageux de traiter les chaînes comme des objets immuables .
  • Vous ne pouvez pas supposer que la chaîne source n'est pas vide. Il ne peut contenir qu'un seul caractère de fin null.
  • Le tampon de destination peut contenir des déchets non initialisés lorsque la fonction est appelée. Le vérifier pour la terminaison nulle n'a aucun sens.
  • La documentation du code source doit indiquer que le tampon de destination doit être suffisamment grand pour contenir la chaîne coupée. Le moyen le plus simple de le faire est de le rendre aussi gros que la chaîne non coupée.
  • Le tampon de destination doit contenir une chaîne terminée par un caractère null sans espaces lorsque la fonction est effectuée.
  • Considérez si vous souhaitez supprimer tous les caractères d'espacement ou juste les espaces ' '.
  • La programmation en C n’est pas une concurrence pour déterminer qui peut regrouper autant d’opérateurs que possible sur une seule ligne. C'est plutôt le contraire: un bon programme C contient un code lisible (toujours la qualité la plus importante) sans sacrifier l'efficacité du programme (assez important).
  • Pour cette raison, vous n'obtenez aucun point bonus pour cacher l'insertion d'une fin nulle de la chaîne de destination, en la laissant faire partie du code de copie. Rendez explicite l'insertion de la terminaison NULL pour montrer que vous n'avez pas réussi à le faire correctement par accident.

Ce que je ferais:

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

Dans ce code, la chaîne source "str_untrimmed" est laissée intacte, ce qui est garanti par l'utilisation de const correcte. Il ne se bloque pas si la chaîne source ne contient rien d'autre qu'une fin nulle. Il termine toujours null par la chaîne de destination.

L'attribution de mémoire est laissée à l'appelant. L'algorithme doit uniquement se concentrer sur le travail prévu. Il supprime tous les espaces blancs.

Il n'y a pas d'astuces subtiles dans le code. Il n'essaie pas de regrouper autant d'opérateurs que possible sur une seule ligne. Cela fera un très pauvre candidat pour le IOCCC . Cependant, il produira à peu près le même code machine que les versions plus obscures à une ligne.

Lorsque vous copiez quelque chose, vous pouvez toutefois optimiser un bit en déclarant les deux pointeurs comme étant restrict, ce qui est un contrat entre le programmeur et le compilateur, le programmeur garantissant que la destination et la source ne sont pas la même adresse (ou plutôt que les données qu’ils point à ne sont accessibles que par ce pointeur même et non par un autre pointeur). Cela permet une optimisation plus efficace, car le compilateur peut alors copier directement de la source à la destination sans mémoire temporaire.

10
Lundin

En C, vous pouvez remplacer certaines chaînes sur place, par exemple une chaîne renvoyée par strdup ():

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

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

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

Les autres chaînes sont en lecture seule, par exemple celles déclarées dans le code. Vous devrez les copier dans une zone de mémoire nouvellement allouée et remplir la copie en sautant les espaces:

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

Vous pouvez voir pourquoi les gens ont inventé d'autres langues;)

7
Andomar

si vous êtes toujours intéressé, cette fonction supprime les espaces du début de la chaîne et je viens juste de le voir fonctionner dans mon code:

void removeSpaces(char *str1)  
{
    char *str2; 
    str2=str1;  
    while (*str2==' ') str2++;  
    if (str2!=str1) memmove(str1,str2,strlen(str2)+1);  
}
2
Alfredo
#include <ctype>

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

Remarques;

  • Cela ne gère pas Unicode.
2
quark
#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));
}
1
Narayan Singh

C'est le plus simple auquel je puisse penser (TESTED) et ça marche !!

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

Solution efficace et assez facile:

//Removespaces.
void be_gone_spaces(char *str)
{
    char *p = str;
    do *(*p == ' ' ? str : str++) = *p;
    while (*p++);
}
0
Tomer Wolberg

Je suppose que la chaîne C est dans une mémoire fixe, donc si vous remplacez des espaces, vous devez décaler tous les caractères.

Le plus simple semble être de créer une nouvelle chaîne, de parcourir la chaîne d'origine et de ne copier que des caractères sans espace.

0
stefanB