¿Cómo puedo hacer una comparación de cadenas insensible a mayúsculas y minúsculas en Python?
Me gustaría encapsular la comparación de una cadena regular con una cadena de repositorio usando de una manera muy simple y pitónica. También me gustaría tener la capacidad de buscar valores en un dict hash por cadenas usando cadenas de python regulares.
python
comparison
case-insensitive
Kozyarchuk
fuente
fuente
Σίσυφος
yΣΊΣΥΦΟΣ
, entonces su enfoque falla, porque se supone que esas son las mismas mayúsculas y minúsculas.'ß'.lower() == 'SS'.lower()
es falso.Comparar cadenas de una manera insensible a mayúsculas y minúsculas parece trivial, pero no lo es. Usaré Python 3, ya que Python 2 está subdesarrollado aquí.
Lo primero a tener en cuenta es que las conversiones de eliminación de mayúsculas y minúsculas en Unicode no son triviales. Hay texto para el cual
text.lower() != text.upper().lower()
, como"ß"
:Pero digamos que querías comparar
"BUSSE"
y sin caso"Buße"
. Demonios, probablemente también quieras comparar"BUSSE"
e"BUẞE"
igualar, esa es la nueva forma de capital. La forma recomendada es usarcasefold
:No solo lo use
lower
. Sicasefold
no está disponible, hacer.upper().lower()
ayuda (pero solo un poco).Entonces deberías considerar los acentos. Si su renderizador de fuentes es bueno, probablemente piense
"ê" == "ê"
, pero no es así:Esto se debe a que el acento en este último es un carácter combinado.
La forma más sencilla de lidiar con esto es
unicodedata.normalize
. Probablemente desee utilizar la normalización de NFKD , pero no dude en consultar la documentación. Entonces uno hacePara terminar, aquí se expresa en funciones:
fuente
x.casefold() == y.casefold()
para comparaciones que no distinguen entre mayúsculas y minúsculas (y, lo que es más importante,x == y
para mayúsculas y minúsculas).NFD(toCasefold(NFD(str)))
en ambos lados y (D147, compatibilidad)NFKD(toCasefold(NFKD(toCasefold(NFD(X)))))
en ambos lados. Establece que el interiorNFD
es únicamente para manejar un cierto carácter de acento griego. Supongo que se trata de casos extremos.Usando Python 2, invocando
.lower()
cada cadena u objeto Unicode ...... funcionará la mayor parte del tiempo, pero de hecho no funciona en las situaciones que @tchrist ha descrito .
Supongamos que tenemos un archivo llamado que
unicode.txt
contiene las dos cadenasΣίσυφος
yΣΊΣΥΦΟΣ
. Con Python 2:El carácter Σ tiene dos formas en minúsculas, ς y σ, y
.lower()
no ayudará a compararlas entre mayúsculas y minúsculas.Sin embargo, a partir de Python 3, las tres formas se resolverán en ς, y llamar a lower () en ambas cadenas funcionará correctamente:
Entonces, si te interesan los casos extremos como los tres sigmas en griego, usa Python 3.
(Como referencia, Python 2.7.3 y Python 3.3.0b1 se muestran en las impresiones del intérprete anteriores).
fuente
La sección 3.13 del estándar Unicode define algoritmos para la coincidencia sin mayúsculas y minúsculas.
X.casefold() == Y.casefold()
en Python 3 implementa la "coincidencia sin mayúsculas predeterminada" (D144).El plegado de casos no preserva la normalización de las cadenas en todos los casos y, por lo tanto, la normalización debe hacerse (
'å'
vs.'å'
). D145 presenta la "coincidencia sin mayúsculas canónica":NFD()
se llama dos veces para casos extremos muy poco frecuentes que involucran el carácter U + 0345.Ejemplo:
También hay compatibilidad sin casillas (D146) para casos como
'㎒'
(U + 3392) y "coincidencia sin identificador" para simplificar y optimizar la coincidencia sin case de identificadores .fuente
casefold()
función no implementa el tratamiento de mayúsculas y minúsculas I y mayúsculas I como se describe en Propiedades de plegado de mayúsculas y minúsculas . Por lo tanto, la comparación puede fallar para palabras de idiomas turcos que contienen esas letras. Por ejemplo,canonical_caseless('LİMANI') == canonical_caseless('limanı')
debe volverTrue
, pero vuelveFalse
. Actualmente, la única forma de lidiar con esto en Python es escribir un contenedor de plegado de casos o usar una biblioteca Unicode externa, como PyICU.Vi esta solución aquí usando regex .
Funciona bien con acentos
Sin embargo, no funciona con caracteres unicode que no distinguen entre mayúsculas y minúsculas. Gracias @Rhymoid por señalar que, según tengo entendido, necesita el símbolo exacto, para que el caso sea cierto. El resultado es el siguiente:
fuente
ß
no se encuentre dentroSS
de la búsqueda sin distinción entre mayúsculas y minúsculas es evidencia de que no funciona en absoluto con los caracteres Unicode .El enfoque habitual es utilizar mayúsculas o minúsculas para las búsquedas y comparaciones. Por ejemplo:
fuente
¿Qué hay de convertir a minúsculas primero? puedes usar
string.lower()
.fuente
Σίσυφος
yΣΊΣΥΦΟΣ
no probaría equivalentes, pero debería.fuente
Todo lo que tendrá que hacer es convertir las dos cadenas a minúsculas (todas las letras se convierten en minúsculas) y luego compararlas (suponiendo que las cadenas sean cadenas ASCII).
Por ejemplo:
fuente
Esta es otra expresión regular que he aprendido a amar / odiar durante la última semana, por lo que generalmente importo como (en este caso sí) algo que refleja cómo me siento. hacer una función normal ... pedir entrada, luego usar .... something = re.compile (r'foo * | spam * ', yes.I) ...... re.I (yes.I a continuación) es lo mismo que IGNORECASE pero no puede cometer tantos errores al escribirlo.
Luego, busca su mensaje utilizando expresiones regulares, pero honestamente, eso debería ser solo unas pocas páginas, pero el punto es que el correo no deseado o spam se juntan y se ignora el caso. Luego, si se encuentra alguno, lost_n_found mostrará uno de ellos. si ninguno de los dos, lost_n_found es igual a Ninguno. Si no es igual a ninguno, devuelva el user_input en minúsculas usando "return lost_n_found.lower ()"
Esto le permite emparejar mucho más fácilmente cualquier cosa que sea sensible a mayúsculas y minúsculas. Por último (NCS) significa "a nadie le importa en serio ...!" o no distingue entre mayúsculas y minúsculas ... lo que sea
si alguien tiene alguna pregunta, hágame saber esto ...
fuente