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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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 768
    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 768
    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;
    }

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