2012-05-17 2 views
2

J'ai besoin d'aide pour re module. J'ai modèle:Python: regex: find si existe, else ignore

pattern = re.compile('''first_condition\((.*)\) 
extra_condition\((.*)\) 
testing\((.*)\) 
other\((.*)\)''', re.UNICODE) 

C'est ce qui se passe si je lance regex sur le texte suivant:

text = '''first_condition(enabled) 
extra_condition(disabled) 
testing(example) 
other(something)''' 
result = pattern.findall(text) 
print(result) 
[('enabled', 'disabled', 'example', 'something')] 

Mais si une ou deux lignes ont été manquées, les retours regex liste vide. Par exemple. mon texte est:

text = '''first_condition(enabled) 
other(other)''' 

Ce que je veux:

[('enabled', '', '', 'something')] 

je pourrais le faire dans plusieurs commandes, mais je pense que ce sera plus lent que de le faire dans un regex. Le code original utilise sed, donc c'est très rapide. Je pourrais le faire en utilisant sed, mais j'ai besoin d'une méthode multi-plateforme pour le faire. Est-il possible de faire? Tnanks!

P.S. Il sera également très bien si séquence de chaînes sera libre, non fixé:

text = '''other(other) 
first_condition(enabled)''' 

doit retourner absolument le même:

[('enabled', '', '', 'something')] 
+2

Voulez-vous vraiment que le résultat soit une liste contenant un seul tuple? –

+0

@ Markarkers: non, une seule liste est encore mieux. – ghostmansd

+0

Ou un seul tuple, non nécessaire. – ghostmansd

Répondre

4

Je l'analyser à un dictionnaire premier:

import re 

keys = ['first_condition', 'extra_condition', 'testing', 'other'] 
d = dict(re.findall(r'^(.*)\((.*)\)$', text, re.M)) 
result = [d.get(key, '') for key in keys] 

voir travailler en ligne: ideone

+2

'd = dict (re.findall (r '^ (.*) \ ((. *) \) $ ', texte, re.M)) 'serait plus propre pour la création de dict. De plus, si les valeurs incluent des espaces, le texte «text.split()» devrait être remplacé par «text.split ('\ n')». –

+0

@StevenRumbalski: C'est un peu plus propre, merci. –

+0

Ceci est une réponse très claire. Merci! – ghostmansd

0

Utilisez un groupe non-appariement pour des trucs en option, et faire le groupe facultatif en mettant un point d'interrogation après le groupe.

Exemple:

pat = re.compile(r'a\(([^)]+)\)(?:b\((?P<bgr>[^)]+)\)?') 

Désolé, mais je ne peux pas tester ce moment.

requires ci-dessus une chaîne comme a(foo) et saisit le texte parents groupe 0.

Ensuite, il correspond en option une chaîne comme b(foo) et si elle est adaptée, il sera enregistré en tant que groupe nommé avec le nom: bgr

Notez que je n'ai pas utilisé .* pour faire correspondre à l'intérieur des parenthèses mais [^)]+. Cela arrête définitivement de correspondre quand il atteint le paren de fermeture, et nécessite au moins un caractère. Vous pouvez utiliser [^)]* si les parenthèses peuvent être vides.

Ces modèles sont de plus en plus compliqués, vous pouvez donc utiliser des modèles détaillés avec des commentaires.

Pour avoir plusieurs motifs optionnels pouvant apparaître dans n'importe quel ordre, placez-les tous dans un groupe non-correspondant et séparez-les avec des barres verticales. Vous devrez utiliser des groupes de correspondance nommés car vous ne connaîtrez pas l'ordre. Mettez un astérisque après le groupe qui ne correspond pas pour permettre à n'importe quel nombre de modèles alternatifs d'être présents (y compris zéro si aucun n'est présent).