2 votes

Extraction de nombres décimaux d'une chaîne de caractères avec Python regex

J'ai essayé en utilisant la bibliothèque de Python. A partir d'un fichier, j'obtiens plusieurs lignes qui contiennent des éléments séparés par des barres ('|'). Je les mets dans une liste et ce dont j'ai besoin, c'est d'obtenir les nombres à l'intérieur afin d'opérer avec eux.

Ce serait l'une des cordes que je voudrais diviser :

>>print(line_input)
>>[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]

et mon intention est de former un vecteur avec chacun des éléments entre crochets.

J'ai créé cette expression régulière

>>test_pattern="\|\[(\d*(\.\d+)?), (\d*(\.\d+)?), (\d*(\.\d+)?)]"

mais les résultats sont un peu confus. En particulier, le résultat est

>>vectors = re.findall(test_pattern, line_input)

>>print(vectors)
>>[('240', '', '7821', '', '0', '', '12', '', '605', '', '0', '', '3', ''), ('1.5', '.5', '7881.25', '.25', '0', '', '0', '', '0', '', '0', '', '0', ''), ('23437', '', '76611', '', '0', '', '0', '', '0', '', '605', '', '605', '')]

Je ne comprends pas d'où viennent les espaces blancs ni pourquoi la partie décimale est dupliquée. Je sais que j'ai presque compris, du moins, je suis sûr que c'est un petit détail simple, mais je ne comprends pas.

Merci beaucoup d'avance.

3voto

Brian Stephens Points 4304

Ces blancs sont les décimales vides possibles. Votre vectors contient tous les groupes de capture, qu'ils soient vides ou non. Ainsi, lorsqu'il y a une décimale, vous obtenez une correspondance du groupe extérieur (\d*(\.\d+)?) et un pour le groupe intérieur (\.\d+)? . Faites de l'intérieur un groupe non capturable :

(\d+(?:\.\d+)?)

Remarque : j'ai également modifié le système pour qu'il exige un chiffre avant la décimale (le cas échéant).

1voto

Darthfett Points 1645

Une autre façon de procéder (potentiellement non robuste si le format d'entrée diffère) serait de diviser la chaîne sur ']|[' pour obtenir les listes, puis de la diviser sur ', ' pour obtenir les valeurs :

from decimal import Decimal
input_str = '[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]'

# ignore the first and last '[' and ']' chars, then split on list separators
list_strs = input_str[1:-1].split(']|[')

# Split on ', ' to get individual decimal values
int_lists = [[Decimal(i) for i in s.split(', ')] for s in list_strs]

# int_lists contains a list of lists of decimal values, like the input format

for l in int_lists:
    print(', '.join(str(d) for d in l))

Résultat :

240, 7821, 0, 12, 605, 0, 3
1.5, 7881.25, 0, 543, 876, 0, 121
237, 761, 0, 61, 7, 605, 605

1voto

Bill Bell Points 1357

Regex a sa place. Cependant, les grammaires écrites avec pyparsage sont souvent plus faciles à écrire - et plus faciles à lire.

>>> import pyparsing as pp

Les nombres sont comme des mots composés de chiffres et de caractères de point/arrêt. Ils sont éventuellement suivis de virgules que nous pouvons simplement supprimer.

>>> number = pp.Word(pp.nums+'.') + pp.Optional(',').suppress()

L'une des listes est constituée d'un crochet gauche, que nous supprimons, suivi d'un ou plusieurs chiffres (tels qu'ils viennent d'être définis), suivi d'un crochet droit, que nous supprimons également, suivi d'une barre facultative, également supprimée. (Incidemment, cette barre est, dans une certaine mesure, redondante car le crochet droit ferme la liste).

Nous appliquons Group à l'ensemble de la construction afin que pyparsing organise pour nous les éléments que nous n'avons pas supprimés dans des listes Python séparées.

>>> one_list = pp.Group(pp.Suppress('[') + pp.OneOrMore(number) + pp.Suppress(']') + pp.Suppress(pp.Optional('|')))

L'ensemble des listes n'est qu'une ou plusieurs listes.

>>> whole = pp.OneOrMore(one_list)

Voici l'entrée,

>>> line_input = '[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]'

... que nous analysons en résultat r .

>>> r = whole.parseString(line_input)

Nous pouvons afficher les listes résultantes.

>>> r[0]
(['240', '7821', '0', '12', '605', '0', '3'], {})
>>> r[1]
(['1.5', '7881.25', '0', '543', '876', '0', '121'], {})
>>> r[2]
(['237', '761', '0', '61', '7', '605', '605'], {})

Plus probablement, nous voudrions que les chiffres soient des chiffres. Dans cette situation, nous connaître que les chaînes de caractères dans les listes représentent soit des flottants, soit des entiers.

>>> for l in r.asList():
...     [int(_) if _.isnumeric() else float(_) for _ in l]
... 
[240, 7821, 0, 12, 605, 0, 3]
[1.5, 7881.25, 0, 543, 876, 0, 121]
[237, 761, 0, 61, 7, 605, 605]

0voto

Ajax1234 Points 42210

Vous pouvez essayer ceci :

import re
s = "[240, 7821, 0, 12, 605, 0, 3]|[1.5, 7881.25, 0, 543, 876, 0, 121]|[237, 761, 0, 61, 7, 605, 605]" 
data = re.findall("\d+\.*\d+", s)

Sortie :

['240', '7821', '12', '605', '1.5', '7881.25', '543', '876', '121', '237', '761', '61', '605', '605']

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