python - ¿Cómo hago una comparación de cadenas que no distingue entre mayúsculas y minúsculas?
comparison case-insensitive (11)
¿Cómo puedo hacer una comparación de cadenas que no distingue entre mayúsculas y minúsculas en Python?
Me gustaría encapsular la comparación de una cadena regular a una cadena de repositorio usando de una manera muy simple y Pythonic. También me gustaría tener la capacidad de buscar valores en un dict hash por cadenas que utilizan cadenas de python regulares.
¿Qué hay de convertir a minúsculas primero? puedes usar string.lower()
.
Asumiendo cadenas ASCII:
string1 = ''Hello''
string2 = ''hello''
if string1.lower() == string2.lower():
print "The strings are the same (case insensitive)"
else:
print "The strings are not the same (case insensitive)"
El enfoque habitual es mayúsculas o minúsculas para las búsquedas y comparaciones. Por ejemplo:
>>> "hello".upper() == "HELLO".upper()
True
>>>
Esta es otra expresión regular que he aprendido a amar / odiar durante la última semana, por lo que generalmente importa como (en este caso sí) algo que refleja cómo me siento. realice una función normal ... solicite información, luego use .... algo = re.compile (r''foo * | spam * '', yes.I) ...... re.I (yes.I a continuación) es lo mismo que IGNORECASE pero no puedes cometer tantos errores al escribirlo.
Luego, busca en tu mensaje usando expresiones regulares, pero honestamente eso debería ser un par de páginas, pero el punto es que foo o spam se canalizan y el caso se ignora. Entonces, si se encuentran cualquiera de los dos, entonces perdidos encontrarán uno de ellos. Si ninguno de los dos perdidos entonces 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 hacer coincidir 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 ponme en esto ..
import re as yes
def bar_or_spam():
message = raw_input("/nEnter FoO for BaR or SpaM for EgGs (NCS): ")
message_in_coconut = yes.compile(r''foo*|spam*'', yes.I)
lost_n_found = message_in_coconut.search(message).group()
if lost_n_found != None:
return lost_n_found.lower()
else:
print ("Make tea not love")
return
whatz_for_breakfast = bar_or_spam()
if whatz_for_breakfast == foo:
print ("BaR")
elif whatz_for_breakfast == spam:
print ("EgGs")
He usado esto para lograr algo más útil para comparar dos cadenas:
def strings_iequal(first, second):
try:
return first.upper() == second.upper()
except AttributeError:
if not first:
if not second:
return True
Actualización : Como lo señaló gerrit , esta respuesta tiene algunos errores. Esto fue hace años y ya no recuerdo para qué lo usé. Recuerdo las pruebas de escritura, pero ¿de qué sirven ahora?
La comparación de cadenas en una forma que no distingue entre mayúsculas y minúsculas parece algo trivial, pero no lo es. Usaré Python 3, ya que Python 2 está subdesarrollado aquí.
Lo primero que hay que tener en cuenta es que las conversiones de eliminación de casos en Unicode no son triviales. Hay texto para el que text.lower() != text.upper().lower()
, como "ß"
:
"ß".lower()
#>>> ''ß''
"ß".upper().lower()
#>>> ''ss''
Pero digamos que quería comparar "BUSSE"
y "Buße"
. Demonios, es probable que también quieras comparar "BUSSE"
y "BUẞE"
iguales: esa es la forma de capital más nueva. La forma recomendada es usar casefold
:
help(str.casefold)
#>>> Help on method_descriptor:
#>>>
#>>> casefold(...)
#>>> S.casefold() -> str
#>>>
#>>> Return a version of S suitable for caseless comparisons.
#>>>
No se limite a usar lower
. Si la casefold
no está disponible, hacer .upper().lower()
ayuda (pero solo un poco).
Entonces deberías considerar los acentos. Si su procesador de fuentes es bueno, probablemente piense que "ê" == "ê"
, pero no lo hace:
"ê" == "ê"
#>>> False
Esto es porque en realidad son
import unicodedata
[unicodedata.name(char) for char in "ê"]
#>>> [''LATIN SMALL LETTER E WITH CIRCUMFLEX'']
[unicodedata.name(char) for char in "ê"]
#>>> [''LATIN SMALL LETTER E'', ''COMBINING CIRCUMFLEX ACCENT'']
La forma más sencilla de lidiar con esto es unicodedata.normalize
. Probablemente desee utilizar la normalización NFKD , pero no dude en consultar la documentación. Entonces uno hace
unicodedata.normalize("NFKD", "ê") == unicodedata.normalize("NFKD", "ê")
#>>> True
Para finalizar, aquí esto se expresa en funciones:
import unicodedata
def normalize_caseless(text):
return unicodedata.normalize("NFKD", text.casefold())
def caseless_equal(left, right):
return normalize_caseless(left) == normalize_caseless(right)
Si tiene listas con cadenas y desea comparar las cadenas en una lista diferente con mayúsculas y minúsculas. Aquí está mi solución.
list1 = map(lambda each:each.lower(), list1)
list2 = map(lambda each:each.lower(), list2)
Después de hacer eso, puedes hacer una comparación de cuerdas fácilmente.
Usando Python 2, llamando a .lower()
en cada cadena u objeto Unicode ...
string1.lower() == string2.lower()
... funcionará la mayor parte del tiempo, pero de hecho no funciona en las situaciones que @tchrist ha descrito .
Supongamos que tenemos un archivo llamado unicode.txt
contiene las dos cadenas Σίσυφος
y ΣΊΣΥΦΟΣ
. Con Python 2:
>>> utf8_bytes = open("unicode.txt", ''r'').read()
>>> print repr(utf8_bytes)
''/xce/xa3/xce/xaf/xcf/x83/xcf/x85/xcf/x86/xce/xbf/xcf/x82/n/xce/xa3/xce/x8a/xce/xa3/xce/xa5/xce/xa6/xce/x9f/xce/xa3/n''
>>> u = utf8_bytes.decode(''utf8'')
>>> print u
Σίσυφος
ΣΊΣΥΦΟΣ
>>> first, second = u.splitlines()
>>> print first.lower()
σίσυφος
>>> print second.lower()
σίσυφοσ
>>> first.lower() == second.lower()
False
>>> first.upper() == second.upper()
True
El carácter Σ tiene dos formas en minúscula, ς y σ, y .lower()
no ayudará a compararlas con mayúsculas y minúsculas.
Sin embargo, a partir de Python 3, las tres formas se resolverán en ς, y la llamada a lower () en ambas cadenas funcionará correctamente:
>>> s = open(''unicode.txt'', encoding=''utf8'').read()
>>> print(s)
Σίσυφος
ΣΊΣΥΦΟΣ
>>> first, second = s.splitlines()
>>> print(first.lower())
σίσυφος
>>> print(second.lower())
σίσυφος
>>> first.lower() == second.lower()
True
>>> first.upper() == second.upper()
True
Entonces, si te interesan los casos de borde como los tres sigmas en griego, usa Python 3.
(Para referencia, Python 2.7.3 y Python 3.3.0b1 se muestran en las impresiones del intérprete arriba).
Vi esta solución here utilizando regex .
import re
if re.search(''mandy'', ''Mandy Pande'', re.IGNORECASE):
# is True
Funciona bien con acentos.
In [42]: if re.search("ê","ê", re.IGNORECASE):
....: print(1)
....:
1
Sin embargo, no funciona con caracteres Unicode que no distinguen entre mayúsculas y minúsculas. Gracias a @Rhymoid por señalar que, según tengo entendido, necesita el símbolo exacto para que el caso sea cierto. La salida es la siguiente:
In [36]: "ß".lower()
Out[36]: ''ß''
In [37]: "ß".upper()
Out[37]: ''SS''
In [38]: "ß".upper().lower()
Out[38]: ''ss''
In [39]: if re.search("ß","ßß", re.IGNORECASE):
....: print(1)
....:
1
In [40]: if re.search("SS","ßß", re.IGNORECASE):
....: print(1)
....:
In [41]: if re.search("ß","SS", re.IGNORECASE):
....: print(1)
....:
La sección 3.13 de la norma Unicode define algoritmos para la coincidencia sin casillas.
X.casefold() == Y.casefold()
en Python 3 implementa la "coincidencia sin casete predeterminada" (D144).
Casefolding no conserva la normalización de cadenas en todos los casos y, por lo tanto, la normalización debe realizarse ( ''å''
vs. ''å''
). D145 introduce "el emparejamiento canónico de caseless":
import unicodedata
def NFD(text):
return unicodedata.normalize(''NFD'', text)
def canonical_caseless(text):
return NFD(NFD(text).casefold())
NFD()
se llama dos veces para casos de borde muy poco frecuentes que involucran U + 0345 caracteres.
Ejemplo:
>>> ''å''.casefold() == ''å''.casefold()
False
>>> canonical_caseless(''å'') == canonical_caseless(''å'')
True
También hay compatibilidad de caseless match (D146) para casos como ''㎒''
(U + 3392) y "identifier caseless match" para simplificar y optimizar el caseless emparejamiento de identificadores .
def insenStringCompare(s1, s2):
""" Method that takes two strings and returns True or False, based
on if they are equal, regardless of case."""
try:
return s1.lower() == s2.lower()
except AttributeError:
print "Please only pass strings into this method."
print "You passed a %s and %s" % (s1.__class__, s2.__class__)