Python: cherche une chaîne de caractère

Résolu
Medestrac -  
mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   -

Bonjour,

Je lis des codes data matrix dont les composants sont spécifiés par des préfixes sous la forme '(XX)'

Exemple: (10)215(17)270109 ou (10)215(96)A(L(11)04122024

Je récupère cette chaîne de caractère en input, et je souhaite en extraire les différentes composantes. Je sais trouver le préfixe (10) et sa position dans la chaîne, mais je ne sais pas trouver la position du préfixe suivant.

Je pourrais chercher uniquement le caractère '(', mais je crains qu'il n'apparaisse dans la donnée (par exemple: A)L)

Je voudrais donc chercher la prochaine occurrence de '(**)', les 2 étoiles pouvant être n'importe quel chiffre...

Comment faire en python?

9 réponses

  1. Phil_1857
     

    Bonjour,

    En fait, ça se ferait plutôt comme ceci:

    import re
    
    s = '(10)215(96)A(L(11)04122024'
    pat = "\(([0-9]{2})\)*"
    
    s_digits = re.findall(pat, s)
    for digit in s_digits: print(digit)

    Résultat:

    1
    1. blux Messages postés 2046 Date d'inscription   Statut Modérateur Dernière intervention   3 455
       

      Oui mais en l'absence de plus de précision, on ne sait pas s'il ne veut récupérer que les données entre parenthèses ou tout le reste pour en faire par exemple, un tableau associatif/dictionnaire.

      0
  2. blux Messages postés 2046 Date d'inscription   Statut Modérateur Dernière intervention   3 455
     

    Salut,

    faire un split avec une regex ?


    0
  3. Medestrac
     

    Bonjour,

    Je ne maitrise pas regex, un coup de main ou un lien vers un bon tuto m'intéresse ;-)

    0
  4. Vous n’avez pas trouvé la réponse que vous recherchez ?

    Posez votre question
  5. PierrotLeFou
     

    Si la chaîne est bien une alternance de nombres entre parenthèses suivi d'un autre nombre:
    ligne = "(10)215(17)270109"
    liste = ligne.replace("(", ",(").replace(")", "),").split(",")

    liste.pop(0)    # enlever la chaîne vide au début

    Les  éléments parenthèsés seraient en indices pairs (0, 2, ...) dans une liste.
    On enlève les parenthèses comme suit:
    element = element.replace("(", "").replace(")", "")

    Il faudra ensuite convertir tous les éléments en nombre si requis.

    0
  6. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
     

    Meilleurs vœux à tous et toutes.

    @pierrotlefou StatutMembre ton exemple me retourne cette liste :

    [' (10)', '215(17)', '270109']

    l'exemple de @Phil_1857 StatutMembre est mieux adapté, en simplifiant un peu le pattern :

    re.findall(r"\((\d{2})\)", s)
    0
  7. PierrotLeFou
     

    @Diablo76:

    On s'est croisé. J'ai corrigé entre  temps.

    0
    1. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
       

      Oui avec ton exemple, mais si on reprend une des chaines de caractères proposée par le PO : 

      "(10)215(96)A(L(11)04122024"

      ça donne :

      ['(10)', '215', '(96)', 'A', '(L', '(11)', '04122024']
      0
  8. vry
     

    'lut,

    Sans expressions régulières.

    def find_digits_between_brackets(string):
        i = 0
        values = {}
        while True:
            i = string.find('(', i)
            if i == -1:
                break
            if string[i+1:i+3].isdigit() and string[i+3] == ')':
                values[i+1] = int(string[i+1:i+3])
            i += 1
        return values
    
    s = '(10)215(96)A(L(11)04122024'
    #position => nombre
    print(find_digits_between_brackets(s))

    Peu d'intérêt, mais uniquement pour montrer une autre façon de faire ^-^

    0
    1. Diablo76 Messages postés 344 Date d'inscription   Statut Membre Dernière intervention   140
       

      Certains préfèreront ta méthode, car beaucoup plus lisible qu'une expression régulière.

      Pour le fun en reprenant ton idée du dictionnaire pour y stocker l'indice :

      import re
      
      def find_digits_between_brackets(string):
          pattern = re.compile(r"\((\d{2})\)")
          return {match.start(1): int(match.group(1)) for match in pattern.finditer(string)}
      
      s = "(10)215(96)A(L(11)04122024"
      
      # position => nombre
      print(find_digits_between_brackets(s))
      
      1
  9. mamiemando Messages postés 33228 Date d'inscription   Statut Modérateur Dernière intervention   7 940
     

    Bonjour,

    Réponse courte

    En croisant les idées de @blux StatutModérateur (#3) et PierrotLeFou (#6), on peut écrire plus simplement :

    import re
    
    s = "(10)215(96)A(L(11)04122024"
    print(s)
    
    r = re.compile(r"\(\d+\)")
    pairs = [
        (m.start(), m.end())
        for m in re.finditer(r, s)
    ]
    start = 0
    for (i, j) in pairs:
        outside = s[start:i]
        inside = s[i:j]
        if outside:
            print(f"outside = {outside}")
        print(f"inside = {inside}")
        start = j
    outside = s[j:]
    print(f"outside = {outside}")

    Résultat :

    (10)215(96)A(L(11)04122024
    inside = (10)
    outside = 215
    inside = (96)
    outside = A(L
    inside = (11)

    Réponse détaillée

    Étant donné la boucle que ça donne, ça peut valoir le coup de faire une fonction avec les callbacks adéquates. Le code devient :

    import re
    
    RE_DATA_MATRIX = re.compile(r"\(\d+\)")
    
    class ParseDataMatrixVisitor:
        def on_inside(s, i, j):
            pass
        def on_outside(s, i, j):
            pass
    
    class DefaultParseDataMatrixVisitor(ParseDataMatrixVisitor):
        def inside(self, s: str, i: int, j: int):
            print("Inside", s[i:j])
        def outside(self, s: str, i: int, j: int):
            print("Outside", s[i:j])
    
    def parse_data(s, vis: ParseDataMatrixVisitor = None):
        if vis is None:
            vis = DefaultParseDataMatrixVisitor()
        pairs = [
            (m.start(), m.end())
            for m in re.finditer(RE_DATA_MATRIX, s)
        ]
        start = 0
        for (i, j) in pairs:
            if start < i:
                vis.outside(s, start, i)
            vis.inside(s, i, j)
            start = j
        vis.outside(s, j, None)
    
    if __name__ == "__main__":
        s = "(10)215(96)A(L(11)04122024"
        print(s)
        vis = DefaultParseDataMatrixVisitor()
        parse_data(s, vis)

    Réponse finale

    À présent, tout est prêt pour faire ce qu'on veut de ces données. Si par exemple, on veut reconstituer un dictionnaire on écrit juste le visiteur adéquat, voici ce qu'on peut écrire :

    import re
    
    RE_DATA_MATRIX = re.compile(r"\(\d+\)")
    
    class ParseDataMatrixVisitor:
        def on_inside(s, i, j):
            pass
        def on_outside(s, i, j):
            pass
    
    class DictParseDataMatrixVisitor(ParseDataMatrixVisitor):
        def __init__(self):
            self.last_key = None
            self.dict = dict()
        def inside(self, s: str, i: int, j: int):
            self.last_key = s[i:j].lstrip("(").rstrip(")")
        def outside(self, s: str, i: int, j: int):
            last_value = s[i:j]
            self.dict[self.last_key] = last_value
    
    def parse_data(s, vis: ParseDataMatrixVisitor = None):
        if vis is None:
            vis = DefaultParseDataMatrixVisitor()
        pairs = [
            (m.start(), m.end())
            for m in re.finditer(RE_DATA_MATRIX, s)
        ]
        start = 0
        for (i, j) in pairs:
            if start < i:
                vis.outside(s, start, i)
            vis.inside(s, i, j)
            start = j
        vis.outside(s, j, None)
    
    if __name__ == "__main__":
        s = "(10)215(96)A(L(11)04122024"
        print(s)
        vis = DictParseDataMatrixVisitor()
        parse_data(s, vis)
        print(vis.dict)

    Résultat :

    (10)215(96)A(L(11)04122024
    {'10': '215', '96': 'A(L', '11': '04122024'}

    Bonne chance

    0