IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

[Chaînes de caractères] Retirer des caractères indésirables


Sujet :

C

  1. #1
    Membre éclairé
    Inscrit en
    Septembre 2008
    Messages
    384
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 384
    Par défaut [Chaînes de caractères] Retirer des caractères indésirables
    Bonjour,

    Je cherche à épurer une chaîne de caractères assez longue (60) de caractères indésirables.
    La chaîne se présente se compose de caractères 'DC2' de la position 0 à la position X, puis ensuite les caractères utiles arrivent et la chaîne se termine par \0.

    En fait, je cherche à retirer tous les caractères 'DC2' et obtenir une chaîne qui commencerait de la position 0 et qui ne contiendrait que les caractères utiles (non DC2) jusqu'à \0.

    Chaîne de départ :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    RCX[0] = 'DC2';
    RCX[1] = 'DC2';
    RCX[2] = 'DC2';
    RCX[3] = 'DC2';
    RCX[4] = 'DC2';
    RCX[5] = 'DC2';
    RCX[6] = 'T';
    RCX[7] = 'E';
    RCX[9] = 'S';
    RCX[10] = 'T';
    RCX[11] = '\0';
    Chaine une fois traitée :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    RCX[0] = 'T';
    RCX[1] = 'E';
    RCX[2] = 'S';
    RCX[3] = 'T';
    RCX[4] = '\0';
    Pourriez-vous s'il vous plaît m'indiquer la méthode la plus rapide pour effectuer cela ?
    Je vous remercie.

  2. #2
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 748
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 748
    Par défaut
    Ce n'est pas méchant

    1) Recherche du premier caractère non 'DC2' (en partant de 0) avec une boucle for -> tu mémorises cette position dans une variable du style pos_start.
    2 - 0) Si tu ne connais pas le longueur de ta chaîne, tu vas jusqu'au premier '\0' avec un compteur -> len.
    2 - 1) memcpy de memcpy(RCX, (RCX + pos_start), (len - pos_start + 1));.
    3) realloc realloc(RCX, (len - pos_start + 1));. (*)

    Après ajouter un test si (len - pos_start + 1) > 0 pour s'assurer qu'il y a une recopie à faire.

    Et si memcpy pose problème avec un traitement "sur place", remplace le avec une boucle for.

    Et je ne suis pas sûr du +1 dans (len - pos_start + 1).


    * -> Éventuellement utiliser un strcpy, si tu es sûr qu'il y a un '\0' final.

  3. #3
    Membre éclairé Avatar de Ngork
    Homme Profil pro
    Barbare IT
    Inscrit en
    Avril 2009
    Messages
    160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Barbare IT
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 160
    Par défaut
    Tu as la fonction standard strrchr(const char *str, int c), déclarée dans string.h, qui retourne un pointeur sur la dernière occurrence d'un caractère dans une chaîne avec nul terminal, donc - DC2 désignant je suppose le caractère Device Control 2 soit le code ASCII 18 ou 0x12 - le code suivant suffit à pointer sur la partie de chaîne nettoyée des caractères DC2 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char *debut = strrchr(chaine, 18);
    if (debut == NULL)
      {
        debut = chaine;
      }
    else
      {
        debut ++;
      }
    Si un pointeur ne te suffit pas (ce que suggère ta question), alors tu peux utiliser memmove (fortement conseillé pour une copie sur le même emplacement mémoire) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    char *debut = strrchr(chaine, 18);
    if (debut != NULL)
      {
         memmove(chaine, debut + 1, strlen(debut));
      }

  4. #4
    Membre éclairé
    Inscrit en
    Septembre 2008
    Messages
    384
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 384
    Par défaut
    Bonjour

    Comme j'utilise du C embarqué, realloc ne fonctionne pas.

    J'ai écris ceci :

    la position pos_start qui est renvoyé est correcte, par contre la ré-ecriture de la chaine avec memcopy n'est pas bonne.
    Pouvez vous m'aider svp ?


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int clean_string(char string[])
    {
        int i, pos_start;
     
        for (i = 0 ; i != strlen(string) ; i++)
        {
            if (string[i] != 0x12)
            {   
            pos_start = i;
            break;  // DC2 character (device control 2)   
            }
        }
     
    memmove(string, string[pos_start + 1], strlen(string) - pos_start);    
    return pos_start;        
    }
    }

  5. #5
    Membre Expert
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Par défaut
    • Ta chaîne commence à pos_start, le + 1 est de trop.
    • memmove attend des adresses: &string[pos_start + 1] (attention aux warnings).
    • Pense au caractère nul, que strlen ne comptabilise pas.


    Tu n'as pas précisé quel devrait être le prototype de la fonction ni qu'elle devait forcément modifier le buffer. Pour moi la méthode la plus rapide ressemblerait à :

    Code trimstr.c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    #include <stdio.h>
     
     
    const char *trim(const char *s, int skip) {
        while (*s && *s == (char)skip)
            ++s;
     
        return s;
    }
     
     
    int main(int argc, char *argv[]) {
        if (argc < 2) {
            printf("Trims all occurences of the first character in a string.\nUsage: trimstr string\n");
            return 1;
        }
     
        const char *original = argv[1],
                   *trimmed  = trim(argv[1], argv[1][0]);
        printf(
            "original string: '%s'\n"
            "trimmed string: '%s'\n",
            original, trimmed);
     
        return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $ gcc -std=c11 -pedantic -Wall -Wextra -o trimstr trimstr.c
    $ trimstr "%%%%%%%%%%Hello, world\!"
    original string: '%%%%%%%%%%Hello, world!'
    trimmed string: 'Hello, world!'
    $

  6. #6
    Membre éclairé Avatar de Ngork
    Homme Profil pro
    Barbare IT
    Inscrit en
    Avril 2009
    Messages
    160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Barbare IT
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 160
    Par défaut
    Pourquoi absolument écrire une boucle et utiliser plusieurs variables quand une fonction dédiée existe, probablement mieux optimisée, non ?
    Cette fonction reprend ton prototype, nettoie la chaîne et te retourne le nombre de DC2 supprimés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int clean_string(char string[])
    {
      char *ptr_start = strrchr(string, 0x12);
     
      if (ptr_start == NULL)
        {
          return 0;
        }
     
      memmove(string, ptr_start + 1, strlen(ptr_start));
     
      return (ptr_start + 1 - string);
    }
    Toutefois, si tu as peu de caractères DC2 et de longues chaînes, c'est plus intéressant de parcourir depuis le premier caractère que depuis le dernier, soit par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    int clean_string(char string[])
    {
      int pos_start = strspn(string, "\x12");
     
      if (pos_start != 0)
        {
          memmove(string, &string[pos_start], strlen(string) + 1 - pos_start);
        }
     
      return pos_start;
    }

  7. #7
    Membre éclairé
    Inscrit en
    Septembre 2008
    Messages
    384
    Détails du profil
    Informations forums :
    Inscription : Septembre 2008
    Messages : 384
    Par défaut
    Merci Ngork,

    Par contre la fonction renvoi 0 pour la position, elle ne devrait pas.
    Le compilateur indique : Warning [2066] type qualifier mismatch in assignment
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    int pos_start = strspn(string, "\x12");
    je pense que strspn fonctionne uniquement avec des chaines et pas des caractères seuls.

    Si j'utilise la fonction pour la detection du dernier caractère DC2 avec la boucle for, la fonction retourne la bonne position
    Par contre le compilateur n'aime pas l'utilisation de memove : Warning [2054] suspicious pointer conversion

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    memmove(string, &string[pos_start], strlen(string) + 1 - pos_start);

    Cette fonction donne le résultat attendu, mais je voudrai maintenant retourné la chaine string modifiée mais je n'y parviens pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    int clean_string(char string[])
    {
        int i, pos_start;
     
     
        for (i = 0 ; i != strlen(string) ; i++)
        {
            if (string[i] != 0x12)
            {   
            pos_start = i;
            break;  // DC2 character (device control 2)   
            }
        }
     
        for (i = 0 ; i != strlen(string)+1 ; i++)
        {
            string[i] = string[i+pos_start]; 
        }
     
    return pos_start;        
    }

  8. #8
    Membre éclairé Avatar de Ngork
    Homme Profil pro
    Barbare IT
    Inscrit en
    Avril 2009
    Messages
    160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Barbare IT
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2009
    Messages : 160
    Par défaut
    Mmm ...
    J'ai testé avec le mini code ci-dessous, les deux fonctions que je t'ai proposées marchent sans problème et je n'ai obtenu aucun warning à la compilation :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include <stdio.h>
    #include <string.h>
     
    int clean_string(char string[]);
     
    int main()
    {
      char test[3][20] = {"Salut", "\x12" "Bonjour", "\x12\x12" "Hello"};
     
      int test0 = clean_string(test[0]);
      printf(" test 0 : %d -> %s\n", test0, test[0]);
     
      int test1 = clean_string(test[1]);
      printf(" test 1 : %d -> %s\n", test1, test[1]);
     
      int test2 = clean_string(test[2]);
      printf(" test 2 : %d -> %s\n", test2, test[2]);
     
      return 0;
    }
     
    int clean_string(char string[])
    {
      int pos_start = strspn(string, "\x12");
     
      if (pos_start != 0)
        {
          memmove(string, &string[pos_start], strlen(string) + 1 - pos_start);
        }
     
      return pos_start;
    }
    Nom : Capture d'écran de 2016-06-11 20:19:13.png
Affichages : 322
Taille : 5,3 Ko

  9. #9
    Membre émérite
    Avatar de Elijha
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Avril 2003
    Messages
    314
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Avril 2003
    Messages : 314
    Par défaut
    Bonjour,

    Sinon, tu peux utiliser la méthode des pointeurs de chaînes (si c'est pour un µC, pas besoin d'utiliser des fonctions de la lib standard). Par exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    /*
        La fonction cleanStrChr va copié la chaine 'str' sur
          elle même sans copier le caratère recherché 'chr'.
     
        Nota: La chaîne str en ressort modifiée !
     */
    char *cleanStrChr(char *str, char chr)
    {   char *ptr = str ;   // Pointeur de recherche
        char *cpy = str ;   // Pointeur de copie
     
        // On fait attention que la chaîne à traiter ne soit pas NULL
        if(str==NULL) return NULL ;
     
        // Tant que le zéro de fin de chaîne n'est pas atteind
        while(*ptr) {
            // Si ce n'est pas le caractère recherché ...
            //      - On copie le pointeur de recherche dans la copie
            //      - On incrémente le pointeur de copie
            if(*ptr != chr ) *cpy++ = *ptr ;
     
            // Caractère suivant
            ptr ++ ;
        }
        // Sans oublier le zéro de fin de chaîne
        *cpy = 0 ;
     
        // On retourne le pointeur sur la chaîne
        return str ;
    }
    Appel à la fonction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    int main(void)
    {
        #define DC2     0x12
     
        // Chaîne à traiter
        char RCX[64] = { DC2, DC2, DC2, DC2, DC2, DC2, 'T', 'E', 'S', 'T', 0 } ;
     
        printf("RCX before : '%s'\n", RCX) ;
     
        // Nettoyage de la chaine
        cleanStrChr(RCX, DC2) ;
     
        printf("RCX after  : '%s'\n", RCX) ;
     
        return 0 ;
    }
    Bonne continuation

Discussions similaires

  1. Réponses: 3
    Dernier message: 02/09/2013, 14h44
  2. Retirer des caractères d'une liste
    Par solorac dans le forum Excel
    Réponses: 2
    Dernier message: 13/03/2008, 15h12
  3. [Artichow] Caractères accentués des légendes
    Par tiantian dans le forum Bibliothèques et frameworks
    Réponses: 8
    Dernier message: 19/07/2007, 16h18
  4. [Remplacer des caractères spéciaux en caractères normaux]
    Par metalamania dans le forum Général Python
    Réponses: 2
    Dernier message: 23/02/2007, 16h18
  5. Réponses: 5
    Dernier message: 21/01/2007, 00h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo