3 votes

Python, analyseur Regex complexe

Je cherche donc à analyser un code à l'aide d'expressions régulières et je me demande s'il existe un moyen plus simple de le faire que ce que j'ai fait jusqu'à présent. Je vais commencer par un exemple de chaîne de caractères à analyser :

T16F161A286161990200040000\r (Ce sont des données qui arrivent par un dispositif série)

Maintenant, je dois d'abord vérifier le code de confirmation, qui sont les 9 premiers caractères du code. Ils doivent être exactement T16F161A2 . Si ces 9 caractères correspondent exactement, je dois vérifier les 3 caractères suivants qui doivent être soit 861 o 37F .

Si ces 3 personnages sont 37F Je lui ai fait faire quelque chose que je dois encore coder, donc nous ne nous soucierons pas de ce résultat.

Cependant, si ces 3 personnages sont 861 J'ai besoin qu'il vérifie les 2 caractères qui suivent pour voir ce qu'ils sont. Ils peuvent être 11 , 14 , 60 , 61 , F0 , F1 o F2 . Chacun d'entre eux fait des choses différentes avec les données qui le précèdent.

Enfin, je dois passer en revue les personnages restants, en les associant tous les deux.

Pour illustrer comment cela fonctionne, voici le code que j'ai créé pour analyser la chaîne de caractères que j'ai postée ci-dessus :

import re

test_string = "T16F161A286161990200040000\r"

if re.match('^T16F161A2.*', test_string):
    print("Match: ", test_string)
    test_string = re.sub('^T16F161A2', '', test_string)
    if re.match('^861.*', test_string):
        print("Found '861': ", test_string)
        test_string = re.sub('^861', '', test_string)
        if re.match('^61.*', test_string):
            print("Found '61' : ", test_string)
            test_string = re.sub('^61', '', test_string)
            for i in range(6):
                if re.match('^[0-9A-F]{2}', test_string):
                    temp = re.match('^[0-9A-F]{2}', test_string).group()
                    print("Found Code: ", temp)
                test_string = re.sub('^[0-9A-F]{2}', '', test_string)

Maintenant, comme vous pouvez le voir dans ce code, après chaque étape, je suis en train d'utiliser re.sub() pour enlever la partie de la ficelle que je venais de chercher. Dans cette optique, ma question est la suivante :

Existe-t-il un moyen d'analyser la chaîne et de trouver les données dont j'ai besoin, tout en conservant la chaîne intacte ? Serait-ce plus ou moins efficace que ce que j'ai actuellement ?

2voto

Thomas Points 2676

Vous n'avez pas besoin d'une regex pour cette tâche, vous pouvez utiliser des blocs if/else et quelques substitutions de chaînes de caractères :

test_string = "T16F161A286161990200040000\r"

def process(input):
  # does a few stuff with 11, 14, 60, 61, F0, F1, or F2
  return

def stringToArray(input):
  return [tempToken[i:i+2] for i in range(0, len(tempToken), 2)]

if not test_string.startswith('T16F161A2'):
  print ("Does not match")
  quit()
else:
  print ("Does match")

tempToken = test_string[9:]

if tempToken.startswith('861'):
  process(tempToken) #does stuff with 11, 14, 60, 61, F0, F1, or F2
  tempToken = tempToken[5:]

  print (stringToArray(tempToken))
else:
  pass

Vous pouvez le voir en direct aquí

0voto

Je recommanderais (parce que vous connaissez la taille de la chaîne) de commencer par la place :

  • Vérifiez les 9 premiers en comparant test_string[:9] == T16F161A2

Je ferais de même pour la deuxième phase (test_string[9:12]). Cette comparaison est beaucoup plus rapide que le regex en fait.

Lorsque vous utilisez une taille connue, vous pouvez appeler votre chaîne comme je l'ai fait ci-dessus. Cela ne "gâchera" pas votre chaîne comme vous le faites maintenant. Par exemple, re.search(pattern, test_string[9:12]).

J'espère que cela vous aidera un peu :)

0voto

tretyose Points 49

En supposant que la chaîne a la même longueur à chaque fois et que les données sont situées dans le même index, vous pouvez simplement utiliser le splicer strings []. Pour obtenir les 9 premiers caractères, vous devez utiliser : test_string[:10] Vous pourriez les définir comme des variables et faciliter la vérification :

confirmation_code = test_string[:10]
nextThree = test_string[10:13]
#check values

Il s'agit d'une méthode intégrée à Python, donc on peut dire qu'elle est plutôt efficace.

0voto

Simon Sagi Points 474

Si vous souhaitez vous en tenir aux expressions rationnelles, cette solution peut convenir :

pattern = re.compile(r'^T16F161A2((861)|37F)(?(2)(11|14|60|61|F0|F1|F2)|[0-9A-F]{2})([0-9A-F]{12})$')
match_result = pattern.match(test_string)

Dans ce cas, vous pouvez vérifier si match_result est un objet de correspondance valide (sinon, il n'y a pas de motif correspondant). Cet objet de correspondance contiendra 4 éléments : - les 3 premiers groupements (861 ou 37F) - données inutiles (ignorez-les) - code de 2 caractères dans le cas où le premier élément est 861 ( None autrement) - 12 derniers chiffres

Pour diviser les 12 derniers chiffres en une seule ligne :

last_12_digits = match_result[3]
last_digits = [last_12_digits[i:i+2] for i in range(0, len(last_12_digits), 2)]

0voto

tobias_k Points 13121

Vous n'avez pas vraiment besoin d'expressions régulières pour cela, puisque vous savez exactement ce que vous recherchez et où vous devez le trouver dans la chaîne. Vous pouvez simplement utiliser le découpage et quelques instructions if/elif/else. Quelque chose comme ceci :

s = test_string.strip()
code, x, y, rest = s[:9], s[9:12], s[12:14], [s[i:i+2] for i in range(14, len(s), 2)]
# T16F161A2, 861, 61, ['99', '02', '00', '04', '00', '00']

if code == "T16F161A2":
    if x == "37F":
    elif x == "861":
        if y == "11":
            ...
        if y == "61":
            # do stuff with rest
    else:
        # invalid
else:
    # invalid

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X