2009-08-14 13 views
1

Je souhaite supprimer des points dans les acronymes mais pas dans les noms de domaine dans une chaîne python. Par exemple, Je veux la chaîneQuelle est la regex pour enlever des points dans les acronymes mais pas dans les noms de domaine?

'a.b.c. [email protected] http://www.test.com' 

pour devenir

'abc [email protected] http://www.test.com' 

Le plus proche regex j'ai fait jusqu'à présent est

re.sub('(?:\s|\A).{1}\.',lambda s: s.group()[0:2], s) 

qui se traduit à

'ab.c. [email protected] http://www.test.com' 

Il semble que f ou l'expression rationnelle ci-dessus pour travailler, je dois changer l'expression rationnelle

(?:\s|\A|\G).{1}\. 

mais il n'y a pas de marqueur de fin de match (\ G) en python.

EDIT: Comme je l'ai mentionné dans mon commentaire, les chaînes n'ont pas de formatage spécifique. Ces chaînes contiennent des conversations humaines informelles et peuvent donc contenir zéro, un ou plusieurs acronymes ou noms de domaine. Quelques erreurs me conviennent si cela m'éviterait de coder un "vrai" analyseur.

+4

à mon humble avis un regex n'est pas le bon outil pour votre problème. C'est peut-être possible mais cela conduit à un code trop complexe. J'utiliserais une approche plus traditionnelle et utiliserais un mélange de regexs et de code python pour diviser la chaîne en ses composants (texte normal, acronymes, ...) et traiter les parties individuellement. Plus verbeux mais aussi plus maintenable. – sebasgo

+0

Je devrais probablement avoir mentionné que j'utilise cela dans le cadre d'une série d'autres regex pour normaliser une séquence de chaînes représentant des conversations humaines informelles. Je peux tolérer quelques erreurs si cela m'éviterait de faire une analyse plus approfondie. – ianalis

+1

Vous devez mieux spécifier le problème. Vos données sont toujours dans trois parties séparées par des espaces, et vous voulez seulement affecter la première partie? Ou avez-vous besoin d'appliquer cela à du texte arbitraire? Si plus tard, comment définiriez-vous un acronyme? Seulement des lettres uniques? Si oui, que prévoyez-vous avec http://a.b.example.com? Ou est-ce que vous voulez supprimer les périodes intégrées, sauf si vous savez que cela fait partie d'un nom de domaine? Mais cela ne fait que poser la question: quand fait-il partie d'un nom de domaine: Après @ ou http: //? Qu'en est-il de ssh: ou d'autres schémas d'URL? Une fois défini, n'importe lequel d'entre eux serait une regex facile. – MtnViewMark

Répondre

1

Ce qui suit a fonctionné pour moi (merci à Bart pour sa réponse):

re.sub('\.(?!(\S[^. ])|\d)', '', s) 

Cela ne supprimera pas un point si elle est le premier caractère d'un mot ou un acronyme.

2

Je vous suggère de diviser la chaîne en '@' (ou tout autre caractère qui a du sens), faites la substitution sur la première partie, puis remettez la chaîne en place. Je pense que cela montrera mieux l'intention du code qu'une expression rationnelle complexe. Quelque chose comme ça, peut-être:

string='a.b.c. [email protected] http://www.test.com' 
left, rest = string.split("@",1) 
left = left.replace(".","") 
result="%[email protected]%s" % (left, rest) 
2

Vous pouvez simplement supprimer DOTS qui n'ont pas deux [az] lettres (ou plus) devant eux:

\.(?![a-zA-Z]{2}) 

Mais cette volonté bien sûr supprimer le premier point à l'adresse suivante:

[email protected]

Vous pouvez résoudre ce problème en faisant:

\.(?![a-zA-Z]{2}|[^\[email protected]]*[email protected]) 

mais je suis sûr qu'il y aura beaucoup plus de ces cas de coin.

+0

Merci pour cette suggestion. C'était la base de ma réponse. Cela m'est venu à l'esprit auparavant, mais je me trompe en ne le poursuivant pas. – ianalis

5

Si vos données sont toujours formatées comme ceci, pourquoi ne pas diviser vos données en 3 parties en les séparant sur l'espace.

Ensuite, il est plutôt trivial de supprimer les points du premier élément et d'utiliser join pour réorganiser les parties.

+1

Ce n'est pas toujours formaté comme ça. Je vais l'utiliser sur des conversations humaines informelles comme mentionné dans mon commentaire nouvellement ajouté. – ianalis

0

Pas aussi élégant comme re.sub() simple, mais essayez ceci:

import re 

s='a.b.c. [email protected] http://www.test.com' 
m=re.search('(.*?)(([a-zA-Z]\.){2,})(.*)', s) 

if m: 
    replacement=''.join(m.group(2).split('.')) 
    s=m.group(1)+replacement+m.group(4) 

print s 

Il suppose qu'il n'y a pas plus d'un acronyme par chaîne, mais vous pouvez toujours l'exécuter à plusieurs reprises.

1

manière non regex:

>>> S = 'a.b.c. [email protected] http://www.test.com' 
>>> ' '.join(w if '@' in w or ':' in w else w.replace('.', '') for w in S.split()) 
'abc [email protected] http://www.test.com' 

(Nécessite des espaces pour séparer sur, mais - donc si vous aviez quelque chose comme des virgules sans espaces, il pourrait manquer un peu.)

Questions connexes