2010-03-11 5 views
1

Comment puis-je filtrer une chaîne dans c? Je veux enlever tout ce qui n'est pas [a-z0-9_].Chaîne de filtre dans C

int main(int argc, char ** argv) { 
    char* name = argv[1]; 
    // remove anything that isn't [a-z0-9_] 

    printf("%s", name); 
} 
+0

Cela ressemble à des devoirs, pourquoi ne pas essayer d'abord une solution? – Tom

+0

Je suis parfaitement OK en marchant la chaîne et en remplaçant les caractères, puis en compactant les zéros, mais j'espérais quelque chose d'un peu plus maintenable. –

Répondre

1
char *src, *dst; 
for (src = name, dst = name; *src; src++) { 
    if ('a' <= *src && *src <= 'z' 
    || '0' <= *src && *src <= '9' 
    || *src == '_') *dst++ = *src; 
} 
*dst = '\0'; 

EDIT: Plusieurs petites révisions. J'espère avoir les bugs maintenant.

+0

Pas un problème pour la grande majorité des ordinateurs du monde mais le standard C ne signifie nullement que a-z soit des caractères contigus. – paxdiablo

+0

Assez vrai. Je suppose que la chose vraiment sûre à faire dans ce cas serait de construire un tableau de 256 'booléens' (comme ce qui est dans ctype) avec 'vrai' ensemble pour exactement les chars voulus, et d'utiliser cela pour faire la vérification. Ou mieux encore, utilisez 'islower()' et 'isdigit()' comme le faisait caf. Sa solution est vraiment meilleure. –

+0

Je suis allé avec celui-ci sauf que j'ai utilisé 'islower' et' isdigit' au lieu du test de portée. Merci! –

0

La bibliothèque standard C ne fournit aucun support pour les expressions régulières.
Vous devrez soit télécharger une bibliothèque RegEx en C (une très courante est PCRE), ou le faire en boucle (plus facile dans le cas présent, puisque les expressions recherchées sont toutes des caractères uniques, donc pas de retour en arrière) .

L'approche en boucle ressemblerait à quelque chose comme:

int main(int argc, char ** argv) { 
    char* name = argv[1]; 

    // remove anything that isn't [a-z0-9_] 
    char strippedName[200]; 
    int iIn, iOut; // subscript in Name and StrippedName respectively 

    iIn = iOut = 0; 
    while (name[iIn] != '\0' && iOut < (sizeof(strippedName) + 1)) { 
     // some condition defining a desirable character 
     // BTW, this condition should actually be 
     // if (islower(name[iIn]) || isdigit(name[iIn] || name[iIn] == '_') 
     // to match the OP's requirement exactly 
     if (isalnum(name[iIn]) || name[iIn] == '_') 
     strippedName[iOut++] = name[iIn]; 
     iIn++; 
    } 
    strippedName[iOut++] = '\0'; 

    printf("%s", strippedName); 
} 

D'autres expressions régulières dans la langue C (autre que PCRE mentionné plus haut):

+0

Un moteur regex est toujours bon à avoir dans votre dépôt mais je pense que c'est comme essayer de tuer une mouche avec un lance-roquettes dans ce cas :-) – paxdiablo

+0

@paxdiablio: accepté; Étant incertain du contexte de la question du PO, j'ai énuméré les deux. – mjv

+0

En pensant au contexte de l'OP, cela ressemble de plus en plus à des devoirs ... J'aurais aimé avoir répondu moins directement (ou l'avoir entièrement intégré). – mjv

0

Consultez ctype pour les fonctions permettant de tester chaque caractère dans une boucle.

+0

'cctype' est un en-tête C++, mais la question est étiquetée comme' c', donc l'en-tête qu'il devrait utiliser est 'ctype.h'. – dreamlax

+0

@dreamlax: Correction de fautes d'orthographe. Cependant, si vous regardez attentivement la page Web, il est dit cctype (ctype.h). Ils sont la même chose. –

+0

@ C.D. Reimer: Ce n'est pas la même chose car vous ne pouvez pas inclure 'cctype' en utilisant un compilateur C. L'en-tête 'cctype' peut contenir une syntaxe spécifique à C++; et sur mon système c'est le cas. En fait, mon en-tête 'ctype.h' définit aussi une autre fonction (' isblank', introduite en C99) sur mon en-tête 'cctype'. – dreamlax

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

int main(int argc, char ** argv) 
{  
    char *name, *inp, *outp; 

    if (argc < 2) 
    { 
     fprintf(stderr, "Insufficient arguments.\n"); 
     return 1; 
    } 

    inp = argv[1]; 
    name = malloc(strlen(inp) + 1); 
    outp = name; 

    if (!name) 
    { 
     fprintf(stderr, "Out of memory.\n"); 
     return 2; 
    } 

    while (*inp) 
    { 
     if (islower((unsigned char)*inp) || isdigit((unsigned char)*inp) || *inp == '_') 
      *outp++ = *inp; 
     inp++; 
    } 

    *outp = '\0'; 

    puts(name); 
    free(name); 

    return 0; 
} 
+0

une raison de faire une nouvelle chaîne au lieu de le faire inplace? –

+1

Pas vraiment, modifier '* argv' semble juste un peu grossier;) – caf

+0

Pourquoi avez-vous quelque chose à modifier? Examinez simplement chaque caractère d'entrée et de sortie seulement les valides. – dreamlax

1

Si vous voulez juste enlever les caractères indésirables de premier argument, il n'y a pas besoin d'allocation de mémoire, juste marcher à travers le caractère par caractère chaîne d'entrée. Et, si vous savez que vous travaillerez dans un environnement ASCII (ou n'importe quel autre supportant a à z), vous pouvez même remplacer les appels de fonction par des versions plus rapides en vérifiant les plages de caractères. Mais, je ne vois pas l'augmentation de la vitesse comme suffisante pour justifier le code non portable.

#include <stdio.h> 
#include <string.h> 
#include <ctype.h> 
int main(int argc, char ** argv) { 
    int i; 
    char *p; 
    if (argc > 1) { 
     for (p = argv[1]; *p != '\0'; p++) { 
      if (islower(*p) || isdigit(*p) || *p == '_') { 
       putchar (*p); 
      } 
     } 
     putchar ('\n'); 
    } 
    return 0; 
} 
+0

J'aime votre boucle sauf pour le putchar. Je vais le remettre dans la chaîne d'origine. –