2012-02-16 15 views
6

me gustaría cambiar todos los caracteres acentuados en caracteres no acentuadas:¿Se puede reemplazar una cadena por un diccionario?

conversion_dict = {"ä": "a", "ö": "o", "ü": "u","Ä": "A", "Ö": "O", "Ü": "U", 
        "á": "a", "à": "a", "â": "a", "é": "e", "è": "e", "ê": "e", 
        "ú": "u", "ù": "u", "û": "u", "ó": "o", "ò": "o", "ô": "o", 
        "Á": "A", "À": "A", "Â": "A", "É": "E", "È": "E", "Ê": "E", 
        "Ú": "U", "Ù": "U", "Û": "U", "Ó": "O", "Ò": "O", "Ô": "O","ß": "s"} 

¿Hay una manera de hacer algo como "paragraph of text".replace([conversion_dict])?

+0

¿Por qué no 'í',' Í', ... 'Ï'? – danihp

+0

Lo que has mostrado no es "todo". ¿Cuál es el propósito? ¿Estás usando Python 2.xo 3.x? –

+0

Creo que hay algo en la biblioteca estándar de Python para hacer esto: http://www.tutorialspoint.com/python/string_translate.htm – user1277476

Respuesta

8

método preferido módulo de uso de terceros

Una alternativa mucho mejor que el método de abajo es utilizar el impresionante unidecode módulo:

>>> import unidecode 
>>> somestring = u"äüÊÂ" 
>>> unidecode.unidecode(somestring) 
'auEA' 

incorporado, método ligeramente peligrosos

A partir de su pregunta de que está buscando normalizar los caracteres Unicode, en realidad hay una buena forma integrada de hacer esto:

>>> somestring = u"äüÊÂ" 
>>> somestring 
u'\xe4\xfc\xca\xc2' 
>>> import unicodedata 
>>> unicodedata.normalize('NFKD', somestring).encode('ascii', 'ignore') 
'auEA' 

Mira la documentación para unicodedata.normalize.

Tenga en cuenta, sin embargo, que puede haber algunos problemas con esto. Ver this post para una buena explicación y algunas soluciones.

Vea también, latin-1-to-ascii para las alternativas.

+0

Este es un horroroso kludge. Utiliza efectos colaterales involuntarios y no hace todo el trabajo una vez que los requisitos se extravían en el mundo real de la ascensión del texto latino. –

+1

@JohnMachin ¿podría elaborar o proporcionar un enlace para que pueda obtener más información al respecto? – David542

+1

@JohnMachin o podría sugerir una mejor alternativa en lugar de simplemente downvoting? – jterrace

5
for k, v in conversion_dict.items(): 
    txt = txt.replace(k, v) 

ETA: Esto no es "horriblemente" lento en absoluto. Aquí hay un temporizador para un caso de juguetes, donde estamos sustituyendo la cadena 100000 personaje usando un diccionario que tiene asignaciones de 56 caracteres en ella, donde ninguno de los personajes están en la cadena:

import timeit 

NUM_REPEATS = 100000 

conversion_dict = dict([(chr(i), "C") for i in xrange(100)]) 

txt = "A" * 100000 

def replace(x): 
    for k, v in conversion_dict.items(): 
     x = x.replace(k, v) 

t = timeit.Timer("replace(txt)", setup="from __main__ import replace, txt") 
print t.timeit(NUM_REPEATS)/NUM_REPEATS, "sec/call" 

En mi ordenador me sale el tiempo de ejecución

0.0056938188076 sec/call 

Así que una dos centésima de segundo para una cadena de 100.000 caracteres. Ahora, algunos de los personajes en realidad estarán en la cadena, y esto lo hará más lento, pero en casi cualquier situación razonable los personajes reemplazados serán mucho más raros que otros personajes. Aún así, la respuesta de jterrace es perfecta.

+2

Esto sería terriblemente lento. –

+0

Eso depende de la longitud de la cadena y del diccionario. –

+0

Si 'replace()' no reemplaza nada, devolverá la cadena original que pasó. Si tiene que reemplazar algo, tendrá que * copiar * toda la cadena (las cadenas son inmutables). Como esto no ocurre en absoluto en su código de ejemplo, sus tiempos no son tan significativos. (De todos modos, los tiempos generalmente solo son significativos cuando * compara * dos enfoques diferentes.) –

0

Tal vez algo como esto funcionará? No lo he probado, pero parece una solución simple.

for key in string: 
    if key in dict: 
     string = string.replace(key, dict[key]) 
0

Cualquier solución ignorando la codificación de fuente y la codificación de entrada será formalmente correcta, pero puede fallar con facilidad haciendo su trabajo.

Primero debe asegurarse de conocer la codificación de la entrada, luego debe asignarla a la codificación en la que escribió el mapa, y entonces todo podría estar bien. Puede usar como codificación interna unicode y convertir la conocida codificación de entrada en ella.

Pruebe reading this sobre el asunto.

4

Esto es un VFAQ. Ver p. this SO question o google "python asciify" o "python a centavo".

Para producir un diccionario decente para usar con unicode.translate, necesita un enfoque que descubra automáticamente los casos fáciles y encuentre aquellos en los que necesita realizar una entrada manual. Un buen enfoque es atravesar el BMP mirando lo que produce el unicodedata.name(the_ordinal, "").

descubrimiento automático: re.match("LATIN (SMALL|CAPTTAL) LETTER ([A-Z]) WITH ", name)

De lo contrario, si se obtiene un partido con "LATIN (SMALL|CAPTTAL) LETTER [A-Z].+", necesita una entrada manual.

Nota importante: unicode.translate utiliza un "mapeo de ordinales Unicode a Unicode ordinales, cadenas Unicode o nada" ... para que pueda reemplazar, por ejemplo, capital THORN por "Th".

He aquí por qué el uso de unicodedata.normalize no es una buena idea:

personajes cuyo primer carácter de la normalización no está en el rango ASCII son despojados a cabo. Esto incluye no solo todos los signos de puntuación (que pueden no interesarle) sino letras que NO estén "acentuadas", p. ß

>>> from unicodedata import name, normalize 
>>> for i in range(0xA0, 0x100): 
...  c = unichr(i) 
...  a = normalize('NFKD', c).encode('ascii', 'ignore') 
...  if not a: 
...   print("FAIL: U+%04X %s" % (i, name(c))) 
... 
FAIL: U+00A1 INVERTED EXCLAMATION MARK 
FAIL: U+00A2 CENT SIGN 
FAIL: U+00A3 POUND SIGN 
FAIL: U+00A4 CURRENCY SIGN 
FAIL: U+00A5 YEN SIGN 
FAIL: U+00A6 BROKEN BAR 
FAIL: U+00A7 SECTION SIGN 
FAIL: U+00A9 COPYRIGHT SIGN 
FAIL: U+00AB LEFT-POINTING DOUBLE ANGLE QUOTATION MARK 
FAIL: U+00AC NOT SIGN 
FAIL: U+00AD SOFT HYPHEN 
FAIL: U+00AE REGISTERED SIGN 
FAIL: U+00B0 DEGREE SIGN 
FAIL: U+00B1 PLUS-MINUS SIGN 
FAIL: U+00B5 MICRO SIGN 
FAIL: U+00B6 PILCROW SIGN 
FAIL: U+00B7 MIDDLE DOT 
FAIL: U+00BB RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK 
FAIL: U+00BF INVERTED QUESTION MARK 
FAIL: U+00C6 LATIN CAPITAL LETTER AE 
FAIL: U+00D0 LATIN CAPITAL LETTER ETH 
FAIL: U+00D7 MULTIPLICATION SIGN 
FAIL: U+00D8 LATIN CAPITAL LETTER O WITH STROKE 
FAIL: U+00DE LATIN CAPITAL LETTER THORN 
FAIL: U+00DF LATIN SMALL LETTER SHARP S <<<<<<<<<<========== ß 
FAIL: U+00E6 LATIN SMALL LETTER AE 
FAIL: U+00F0 LATIN SMALL LETTER ETH 
FAIL: U+00F7 DIVISION SIGN 
FAIL: U+00F8 LATIN SMALL LETTER O WITH STROKE 
FAIL: U+00FE LATIN SMALL LETTER THORN 
>>> 
Cuestiones relacionadas