Quiero eliminar puntos en acrónimos pero no en nombres de dominio en una cadena de python. Por ejemplo, quiero la cadena

'a.b.c. test@test.com http://www.test.com'

Convertirse

'abc test@test.com http://www.test.com'

La expresión regular más cercana que hice hasta ahora es

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

Que resulta a

'ab.c. test@test.com http://www.test.com'

Parece que para que la expresión regular anterior funcione, necesito cambiar la expresión regular a

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

Pero no hay un marcador de final de partido (\ G) en python.

EDITAR: Como he mencionado en mi comentario, las cadenas no tienen un formato específico. Estas cadenas contienen conversaciones humanas informales y, por lo tanto, pueden contener cero, uno o varios acrónimos o nombres de dominio. Algunos errores están bien si me salvaría de codificar un analizador "real".

1
Christian Alis 14 ago. 2009 a las 21:28

6 respuestas

La mejor respuesta

Lo siguiente funcionó para mí (con agradecimiento a Bart por su respuesta):

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

Esto no eliminará un punto si es el primer carácter de una palabra o acrónimo.

1
Christian Alis 14 ago. 2009 a las 22:21

Una forma no regex:

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

(Sin embargo, requiere espacios para dividirse, por lo que si tuviera algo como comas sin espacios, podría perder algunos).

1
Anon 15 ago. 2009 a las 00:12

Simplemente puede eliminar los DOTS que no tienen dos letras [a-z] (o más) delante de ellos:

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

Pero eso, por supuesto, también eliminará el primer DOT de la siguiente dirección:

Nombre.i@foo.bar

Podrías arreglar eso haciendo:

\.(?![a-zA-Z]{2}|[^\s@]*+@)

Pero estoy seguro de que habrá muchos más casos similares.

2
Bart Kiers 14 ago. 2009 a las 17:39

Si sus datos siempre están formateados de esta manera, ¿por qué no dividir sus datos en 3 partes dividiéndolos en el espacio?

Entonces es bastante trivial eliminar los puntos del primer elemento y usar join para volver a combinar las partes.

5
chollida 14 ago. 2009 a las 17:40

Le sugiero que divida la cadena en '@' (o cualquier carácter que tenga sentido), haga la sustitución en la primera parte y luego vuelva a unir la cadena. Creo que eso mostrará la intención del código mejor que una expresión regular compleja. Algo como esto, tal vez:

string='a.b.c. test@test.com http://www.test.com'
left, rest = string.split("@",1)
left = left.replace(".","")
result="%s@%s" % (left, rest)
2
Bryan Oakley 14 ago. 2009 a las 18:49

No es tan elegante como un simple re.sub(), pero prueba esto:

import re

s='a.b.c. test@test.com 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

Se supone que no hay más de un acrónimo por cadena, pero siempre se puede ejecutar repetidamente.

0
Head Geek 14 ago. 2009 a las 18:30