2010-08-18 18 views
8

Estoy haciendo un filtro en el que compruebo si una cadena Unicode (codificación utf-8) no contiene caracteres en mayúscula (en todos los idiomas). Me parece bien que la secuencia no contenga ningún personaje encamisado.Python: ¿Cómo comprobar si una cadena Unicode contiene un carácter encajonado?

Por ejemplo: 'Hello!' no pasará el filtro, pero "!" debería pasar el filtro, ya que "!" no es un personaje encajonado

Planeé utilizar el método islower(), pero en el ejemplo anterior, "!". Islower() devolverá False.

De acuerdo con Python Docs, "el método Unicode de python islower() devuelve True si los caracteres encasillados de la cadena Unicode son minúsculos y la cadena contiene al menos un carácter encajonado; de lo contrario, devuelve False".

Dado que el método también devuelve False cuando la cadena no contiene ningún carácter encajonado, es decir. "!", Quiero verificar si la cadena contiene algún carácter encajonado.

Algo como esto ....

string = unicode("[email protected]#$%^", 'utf-8') 

#check first if it contains cased characters 
if not contains_cased(string): 
    return True 

return string.islower(): 

¿Alguna sugerencia para una función contains_cased()?

¿O probablemente un enfoque de implementación diferente?

Gracias!

+0

Parece que la respuesta que ha aceptado es incorrecta. Ver mi respuesta –

Respuesta

6

Here es la primicia sobre Unicode categorías de caracteres.

categorías Letter incluyen:

Ll -- lowercase 
Lu -- uppercase 
Lt -- titlecase 
Lm -- modifier 
Lo -- other 

Tenga en cuenta que Ll <-> islower(); de manera similar para Lu; (Lu or Lt) <-> istitle()

Es posible que desee leer la discusión complicada en la carcasa, que incluye un poco de discusión de las letras Lm.

Tratar ciegamente todas las "letras" como encajonado es demostrablemente incorrecto. La categoría Lo incluye 45301 puntos de código en el BMP (contados usando Python 2.6). Una gran parte de estos sería Hangul Syllables, CJK Ideographs y otros caracteres del este de Asia, muy difícil de entender cómo se podrían considerar "enyesados".

Puede que desee considerar una definición alternativa, basada en el comportamiento (no especificado) de los "caracteres encapsulados" que espera. Aquí es un simple primer intento:

>>> cased = lambda c: c.upper() != c or c.lower() != c 
>>> sum(cased(unichr(i)) for i in xrange(65536)) 
1970 
>>> 

Curiosamente hay 1.216 x 937 x LL y Lu, un total de 2.153 ...posibilidad de seguir investigando lo que realmente significan Ll y Lu.

+0

@John: Wow. Gracias por tu explicación. Me tomó un tiempo entenderlo. Eché un vistazo a su enlace, y creo que tengo que estudiarlo más extensamente. Tengo la sensación de que lo que voy a descubrir me va a obligar a revisar gran parte de mi código. Yikes. Gracias! – Albert

+0

@Albert: No se preocupe. Como he insinuado, primero desarrolle una definición de lo que quiere decir con "entubado". ¿Qué tratamiento diferente aplicará a los caracteres encapsulados en lugar de a los caracteres no encapsulados? Mi definición de ejemplo fue "char que tiene un 'socio' en mayúsculas o minúsculas". Algunas (tal vez todas) la diferencia entre los caracteres de 1970 y 2153 parece deberse a caracteres que se clasifican como 'Ll' porque parecen un carácter en minúscula, pero no tienen un compañero' Lu', y viceversa - debe decidir si estos están "encapsulados" para sus propósitos. Por cierto, puede cambiar su respuesta aceptada :-) –

+0

@John: Bueno, en realidad estoy haciendo una API para mi servicio web. Mi servicio web acepta una clave que se asigna a un registro específico en mi base de datos. La clave distingue entre mayúsculas y minúsculas, y la clave puede estar compuesta por cualquier carácter unicode. Entonces, para normalizar todas las entradas, convertiré todas las consultas clave en minúsculas (si tienen equivalentes en mayúsculas). Una consecuencia de esto es cuando creo las claves de registro (que pueden personalizar mis usuarios), no puedo aceptar ningún carácter en mayúsculas que la función toLower() pueda convertir a minúsculas equivalentes. Así que estoy tratando de hacer un filtro para eso. ¿Alguna sugerencia? – Albert

7
import unicodedata as ud 

def contains_cased(u): 
    return any(ud.category(c)[0] == 'L' for c in u) 
+0

Arg alex, ¿hay algo que no sepas? –

+2

-1 Trata caracteres de Asia oriental como "encajonados". Ver mi respuesta –

+0

+1: solución de trabajo (en comparación con la buena explicación sin código ejecutable de John Machin) – oDDsKooL

1

uso del módulo unicodedata,

unicodedata.category(character) 

devuelve "Ll" para las letras minúsculas y "Lu" para las mayúsculas.

here puede encontrar la lista de categorías de caracteres Unicode

Cuestiones relacionadas