J'ai rencontré un petit problème en utilisant Python Regex.
Supposons que ce soit l'entrée:
(zyx)bc
Ce que j'essaie de réaliser, c'est d'obtenir ce qui se trouve entre les parenthèses en tant que correspondance unique et tout caractère extérieur en tant que correspondance individuelle. Le résultat souhaité serait le suivant:
['zyx','b','c']
L'ordre des matchs doit être conservé.
J'ai essayé d'obtenir cela avec Python 3.3, mais je n'arrive pas à comprendre le bon regex. Jusqu'à présent, j'ai:
matches = findall(r'\((.*?)\)|\w', '(zyx)bc')
print(matches)
donne les résultats suivants:
['zyx','','']
Des idées sur ce que je fais mal?
D'après la documentation de re.findall
:
Si un ou plusieurs groupes sont présents dans le modèle, renvoyez une liste de groupes; ce sera une liste de tuples si le motif a plus d'un groupe.
Pendant que votre expression rationnelle correspond trois fois à la chaîne, le (.*?)
le groupe est vide pour les deux seconds matchs. Si vous voulez la sortie de l'autre moitié de l'expression rationnelle, vous pouvez ajouter un deuxième groupe:
>>> re.findall(r'\((.*?)\)|(\w)', '(zyx)bc')
[('zyx', ''), ('', 'b'), ('', 'c')]
Alternativement, vous pouvez supprimer tous les groupes pour obtenir à nouveau une simple liste de chaînes:
>>> re.findall(r'\(.*?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']
Vous devrez cependant supprimer manuellement les parenthèses.
Jetons un œil à notre sortie en utilisant re.DEBUG
.
branch
literal 40
subpattern 1
min_repeat 0 65535
any None
literal 41
or
in
category category_Word
Aïe, il n'y a qu'un subpattern
mais re.findall
ne sort que subpattern
s s'il en existe un!
a = re.findall(r'\((.*?)\)|(.)', '(zyx)bc',re.DEBUG); a
[('zyx', ''), ('', 'b'), ('', 'c')]
branch
literal 40
subpattern 1
min_repeat 0 65535
any None
literal 41
or
subpattern 2
any None
Mieux. :)
Il ne nous reste plus qu'à en faire le format que vous souhaitez.
[i[0] if i[0] != '' else i[1] for i in a]
['zyx', 'b', 'c']
Les documents mentionnent spécialement le traitement des groupes, donc ne mettez pas de groupe autour du modèle entre parenthèses, et vous obtiendrez tout, mais vous devrez supprimer vous-même les parens des données correspondantes:
>>> re.findall(r'\(.+?\)|\w', '(zyx)bc')
['(zyx)', 'b', 'c']
ou utilisez plus de groupes, puis traitez les tuples résultants pour obtenir les chaînes que vous recherchez:
>>> [''.join(t) for t in re.findall(r'\((.+?)\)|(\w)', '(zyx)bc')]
>>> ['zyx', 'b', 'c']
In [108]: strs="(zyx)bc"
In [109]: re.findall(r"\(\w+\)|\w",strs)
Out[109]: ['(zyx)', 'b', 'c']
In [110]: [x.strip("()") for x in re.findall(r"\(\w+\)|\w",strs)]
Out[110]: ['zyx', 'b', 'c']
D'autres réponses vous ont montré comment obtenir le résultat dont vous avez besoin, mais avec l'étape supplémentaire de suppression manuelle des parenthèses. Si vous utilisez des contournements dans votre expression régulière, vous n'aurez pas besoin de supprimer les parenthèses manuellement:
>>> import re
>>> s = '(zyx)bc'
>>> print (re.findall(r'(?<=\()\w+(?=\))|\w', s))
['zyx', 'b', 'c']
Expliqué:
(?<=\() // lookbehind for left parenthesis
\w+ // all characters until:
(?=\)) // lookahead for right parenthesis
| // OR
\w // any character