Python: cherche une chaîne de caractère

Résolu
Medestrac -  
mamiemando Messages postés 33782 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?

A voir également:

9 réponses

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
blux Messages postés 27161 Date d'inscription   Statut Modérateur Dernière intervention   3 362
 

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
blux Messages postés 27161 Date d'inscription   Statut Modérateur Dernière intervention   3 362
 

Salut,

faire un split avec une regex ?


0
Medestrac
 

Bonjour,

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

0
blux Messages postés 27161 Date d'inscription   Statut Modérateur Dernière intervention   3 362
 

Je ne maitrise pas Python, mais je verrais bien un truc comme ça :

import re
print(re.split(r'(\d+)', s_nums))

Adapté de :

https://note.nkmk.me/en/python-split-rsplit-splitlines-re/#split-a-string-by-regex-resplit

\d veut dire 'digit', donc chiffre et {2} veut dire 2 occurrences de \d, entourées par les parenthèses.


0

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

Posez votre question
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
Diablo76 Messages postés 247 Date d'inscription   Statut Membre Dernière intervention   85
 

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
PierrotLeFou
 

@Diablo76:

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

0
Diablo76 Messages postés 247 Date d'inscription   Statut Membre Dernière intervention   85
 

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
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
Diablo76 Messages postés 247 Date d'inscription   Statut Membre Dernière intervention   85
 

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
mamiemando Messages postés 33782 Date d'inscription   Statut Modérateur Dernière intervention   7 884
 

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