2011-10-04 5 views
-3

Étant donné une chaîne de caractères (en tant qu'argument de fonction), après une combinaison de caractères donnée, j'ai besoin de supprimer la séquence de zéros, si elle est sortie (uniquement pour modifier la chaîne). Par exemple, si la combinaison de caractères est x+, la chaîne 20.301x+000005 doit être convertie en 20.301x+5.Suppression de caractères de la chaîne C

J'ai essayé ceci:

void convertStr(char *analysisBuffer) 
{ 
    char *exp; 

    if((exp = strstr(analysisBuffer,"x+"))!=NULL||(exp = strstr(analysisBuffer,"X+"))!= NULL) 
    { 
     exp += 2; 
     char * zeroIt = exp; 
     while(*zeroIt == '0') 
      ++zeroIt; 
     unsigned int x = exp - analysisBuffer; 
     analysisBuffer[x] = '\0'; 
     strcat(analysisBuffer,zeroIt); 
    } 
} 

Quelqu'un peut-il me conseiller comment mettre en œuvre correctement?

+0

'vous dire Avez-analysisBuffer [x] = '\ 0';' au lieu de 'analysisBuffer [0] = '\ 0';'? – tdk001

+0

Pour réécrire votre exigence: Supprimez tout '0' qui se produit après une séquence donnée. Est-il nécessaire de modifier la chaîne ou une copie est-elle également autorisée? – pmr

+0

only modify string – Yakov

Répondre

3

Ceci est une version qui fonctionne pour plusieurs occurences de l'expression et réduit la taille de la chaîne de sorte qu'aucune mémoire n'est occupée par terminateurs zéro. Ceci est probablement plus lent et complètement inutile, mais vous donne le sentiment génial de faire quelque chose de fantaisie. Clause de non-responsabilité: Je n'ai jamais écrit de C pur depuis longtemps.

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 

char* strip_zero(char* str, const char* startseq) { 
    // while there is an occurence of the substring 
    size_t ssize = strlen(startseq); 
    size_t oldlen = strlen(str) + 1; // account for terminator 
    size_t rems = 0; 
    char* begin = str; 

    while((begin = strstr(begin, startseq))) { 
    // move to the end of the sequence 
    begin += ssize; 
    char* walk = begin; 
    // walk until we reach nonzero 
    while(*walk == '0') { ++walk; ++rems; } 
    // move the string forward 
    memmove(begin, walk, strlen(walk) + 1); 
    } 

    // realloc the string 
    return (char*)realloc(str, oldlen - rems); 
} 

int main(void) 
{ 
    // make a copy so we can modify 
    const char* a = "x+20.301x+00000x+0005x+"; 
    char* foo = (char*)malloc(strlen(a) + 1); 
    strcpy(foo, a); 
    printf("%s \n", foo); 
    foo = strip_zero(foo, "x+"); 
    printf("%s \n", foo); 
    free(foo); 
    return 0; 
} 
+0

+1 c'est pourquoi j'aime C, pour "le sentiment génial de faire quelque chose de fantaisie";) – BlackBear

+0

Cela ne résout pas le problème si la chaîne doit être modifiée et je pense que strcpy avec des chaînes qui se chevauchent peut avoir des résultats indéfinis. –

+0

@Jim Merci, j'ai raté la partie "may not" dans le doc. Je vais arranger ça. Cependant, je ne comprends pas la deuxième partie de votre commentaire. La modification est en place. Si la mémoire doit être conservée, il vous suffit d'ignorer le 'realloc' et tout ira bien. – pmr

1

Quelque chose comme

char * write = str; 
char * read = str; 
while(*read){ 
    while(*read && *read == '0'){ read++; } 
    *write++ = *read++; 
} 
*write = '\0'; 

? (ceci n'est pas testé)

2

Voici un exemple plus complet de ce que vous voulez. J'ai essayé d'améliorer sur quelques articles:

  • Utilisez la fonction strcasestr pour un test insensible à la casse. (Nous avons besoin de #define _GNU_SOURCE pour cela)
  • Utilisez strcat (comme vous l'avez fait) pour ajouter la queue de la chaîne à la tête.
  • Veillez à définir la chaîne sous la forme char test[] = "..." et non char *test = "...", car cette dernière segmentera.
  • Il y a un 'si' pour voir si nous devons sauter un ou plusieurs '0'.
  • Vous pouvez vous débarrasser de la boucle while, en utilisant une fonction comme rindex(), qui donne l'index le plus à droite d'un caractère dans une chaîne.

#define _GNU_SOURCE 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 

    void 
convertStr(char *analysisBuffer) 
{ 
    char *exp = strcasestr(analysisBuffer, "x+"); 

    if (exp) { 
     exp += 2; 
     if (*exp == '0') { 
      while (*exp == '0') { 
       *exp = '\0'; 
       exp++; 
      } 
      strcat(analysisBuffer, exp); 
     } 
    } 
} 

    int 
main(int argc, char *argv[]) 
{ 
    char test[] = "20.301X+0005"; 

    printf("before: %s\n", test); 
    convertStr(test); 
    printf("after : %s\n", test); 

    return EXIT_SUCCESS; 
} 
+0

Mon C est rouillé, mais ne modifie pas une UB littérale? Bien sûr, observer ceci est l'obligation de l'appelant de votre fonction mais c'est ce que fait votre code. – pmr

+0

Oui, si c'était un littéral de chaîne, mais je définis un tableau de chaînes modifiable ici. Pour répondre pleinement à vos préoccupations, consultez la discussion stackoverflow suivante: http: // stackoverflow.com/questions/164194/why-does-simple-c-code-receive-segmentation-fault – Johan

+0

Oublié de dire J'ai effectivement compilé et exécuté ce code, donc je sais que cela fonctionne. J'ai même essayé quelques entrées différentes et utilisé gdb pour voir si j'ai rencontré quelque chose d'étrange. – Johan

1

Au lieu de:

unsigned int x = exp - analysisBuffer; 
    analysisBuffer[x] = '\0'; 
    strcat(analysisBuffer,zeroIt); 

vous pourriez faire:

memmove(exp, zeroIt, strlen(zeroIt) + 1); 
1
size_t strip0(char *buff); 
size_t strip0(char *buff) 
{ 
size_t src,dst; 

for (src=dst=0; buff[dst] = buff[src++] ;dst++) { 
    if ((buff[dst] == 'x' || buff[dst] == 'X') && buff[src] == '+') { 
     buff[++dst] = buff[src++] ; 
     while (buff[src] == '0') src++; 
     } 
    } 
return dst; 
} 

#include <stdio.h> 

int main(int arc, char **argv) 
{ 
char data[] = "100x+003 aap 200x+300 100X+003 noot 200X+300 mies 1234xX+000000000zzz"; 

printf("Org: %s\n", data); 
strip0(data); 
printf("New: %s\n", data); 

return 0; 
} 
Questions connexes