Python: cherche une chaîne de caractère

Résolu

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. 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. Modérateur

      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. Modérateur

    Salut,

    faire un split avec une regex ?


    0
    1. Bonjour,

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

      0
      1. 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
        1. Meilleurs vœux à tous et toutes.

           ton exemple me retourne cette liste :

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

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

          re.findall(r"\((\d{2})\)", s)
          0
          1. @Diablo76:

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

            0
            1. 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
          2. '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. 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
          3. Modérateur

            Bonjour,

            Réponse courte

            En croisant les idées de (#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