que - python mayusculas y minusculas
Diccionario de mayúsculas y minúsculas (8)
¿Consideraría usar string.lower()
en sus entradas y usar un diccionario en minúsculas? Es un poco una solución pirata, pero funciona
Me gustaría que mi diccionario sea insensible a mayúsculas y minúsculas.
Tengo este código de ejemplo:
text = "practice changing the color"
words = {''color'': ''colour'',
''practice'': ''practise''}
def replace(words,text):
keys = words.keys()
for i in keys:
text= text.replace(i ,words[i])
return text
text = replace(words,text)
print text
Salida = práctica cambiando el color
Me gustaría otra cadena, "practice changing the Color"
, (donde el Color
comienza con mayúscula) para dar el mismo resultado.
Creo que hay una forma general de convertir a minúsculas usando mydictionary[key.lower()]
pero no estoy seguro de cómo integrar esto mejor en mi código existente. (Si este fuera un enfoque razonable y simple de todos modos).
Acabo de configurar una función para manejar esto:
def setLCdict(d, k, v):
k = k.lower()
d[k] = v
return d
myDict = {}
Así que en lugar de
myDict[''A''] = 1
myDict[''B''] = 2
Usted puede:
myDict = setLCdict(myDict, ''A'', 1)
myDict = setLCdict(myDict, ''B'', 2)
Luego puede escribir el valor en minúscula antes de buscarlo o escribir una función para hacerlo.
def lookupLCdict(d, k):
k = k.lower()
return d[k]
myVal = lookupLCdict(myDict, ''a'')
Probablemente no sea lo ideal si desea hacer esto a nivel mundial, pero funciona bien si solo es un subconjunto para el que desea utilizarlo.
En mi caso particular, necesitaba una búsqueda de mayúsculas y minúsculas, sin embargo, no quería modificar el caso original de la clave. Por ejemplo:
>>> d = {}
>>> d[''MyConfig''] = ''value''
>>> d[''myconfig''] = ''new_value''
>>> d
{''MyConfig'': ''new_value''}
Puede ver que el diccionario aún tiene la clave original, sin embargo, se puede acceder a mayúsculas y minúsculas. Aquí hay una solución simple:
class CaseInsensitiveKey(object):
def __init__(self, key):
self.key = key
def __hash__(self):
return hash(self.key.lower())
def __eq__(self, other):
return self.key.lower() == other.key.lower()
def __str__(self):
return self.key
Las modificaciones __hash__ y __eq__ son necesarias para obtener y configurar entradas en el diccionario. Esto es crear claves que se agrupan en la misma posición en el diccionario si son iguales a mayúsculas y minúsculas.
Ahora cree un diccionario personalizado que inicialice un CaseInsensitiveKey usando la clave provista:
class CaseInsensitiveDict(dict):
def __setitem__(self, key, value):
key = CaseInsensitiveKey(key)
super(CaseInsensitiveDict, self).__setitem__(key, value)
def __getitem__(self, key):
key = CaseInsensitiveKey(key)
return super(CaseInsensitiveDict, self).__getitem__(key)
o simplemente asegúrese de pasar siempre una instancia de CaseInsensitiveKey como clave cuando use el diccionario.
He modificado la solución simple pero buena con pleasemorebacon (¡gracias!), Haciéndola un poco más compacta, independiente y con actualizaciones menores para permitir la construcción desde {''a'':1, ''B'':2}
y el protocolo __contains__
. Finalmente, dado que se espera que CaseInsensitiveDict.Key
sea una cadena (lo que puede ser sensible a mayúsculas y minúsculas), es una buena idea derivar la clase Key
de la str
, entonces es posible, por ejemplo, volcar CaseInsensitiveDict
con json.dumps
fuera de la caja.
# caseinsensitivedict.py
class CaseInsensitiveDict(dict):
class Key(str):
def __init__(self, key):
str.__init__(key)
def __hash__(self):
return hash(self.lower())
def __eq__(self, other):
return self.lower() == other.lower()
def __init__(self, data=None):
super(CaseInsensitiveDict, self).__init__()
if data is None:
data = {}
for key, val in data.items():
self[key] = val
def __contains__(self, key):
key = self.Key(key)
return super(CaseInsensitiveDict, self).__contains__(key)
def __setitem__(self, key, value):
key = self.Key(key)
super(CaseInsensitiveDict, self).__setitem__(key, value)
def __getitem__(self, key):
key = self.Key(key)
return super(CaseInsensitiveDict, self).__getitem__(key)
Aquí hay una secuencia de comandos de prueba básica para aquellos que les gusta revisar las cosas en acción:
# test_CaseInsensitiveDict.py
import json
import unittest
from caseinsensitivedict import *
class Key(unittest.TestCase):
def setUp(self):
self.Key = CaseInsensitiveDict.Key
self.lower = self.Key(''a'')
self.upper = self.Key(''A'')
def test_eq(self):
self.assertEqual(self.lower, self.upper)
def test_hash(self):
self.assertEqual(hash(self.lower), hash(self.upper))
def test_str(self):
self.assertEqual(str(self.lower), ''a'')
self.assertEqual(str(self.upper), ''A'')
class Dict(unittest.TestCase):
def setUp(self):
self.Dict = CaseInsensitiveDict
self.d1 = self.Dict()
self.d2 = self.Dict()
self.d1[''a''] = 1
self.d1[''B''] = 2
self.d2[''A''] = 1
self.d2[''b''] = 2
def test_contains(self):
self.assertIn(''B'', self.d1)
d = self.Dict({''a'':1, ''B'':2})
self.assertIn(''b'', d)
def test_init(self):
d = self.Dict()
self.assertFalse(d)
d = self.Dict({''a'':1, ''B'':2})
self.assertTrue(d)
def test_items(self):
self.assertDictEqual(self.d1, self.d2)
self.assertEqual(
[v for v in self.d1.items()],
[v for v in self.d2.items()])
def test_json_dumps(self):
s = json.dumps(self.d1)
self.assertIn(''a'', s)
self.assertIn(''B'', s)
def test_keys(self):
self.assertEqual(self.d1.keys(), self.d2.keys())
def test_values(self):
self.assertEqual(
[v for v in self.d1.values()],
[v for v in self.d2.values()])
La respuesta actualmente aprobada no funciona en muchos casos, por lo que no se puede utilizar como un reemplazo de dict
. Algunos puntos difíciles para obtener un reemplazo adecuado de dict
:
- Sobrecargar todos los métodos que involucran claves.
- manejando adecuadamente las claves que no son de cadena
- Manejando adecuadamente el constructor de la clase.
Lo siguiente debería funcionar mucho mejor:
class CaseInsensitiveDict(dict):
@classmethod
def _k(cls, key):
return key.lower() if isinstance(key, basestring) else key
def __init__(self, *args, **kwargs):
super(CaseInsensitiveDict, self).__init__(*args, **kwargs)
self._convert_keys()
def __getitem__(self, key):
return super(CaseInsensitiveDict, self).__getitem__(self.__class__._k(key))
def __setitem__(self, key, value):
super(CaseInsensitiveDict, self).__setitem__(self.__class__._k(key), value)
def __delitem__(self, key):
return super(CaseInsensitiveDict, self).__delitem__(self.__class__._k(key))
def __contains__(self, key):
return super(CaseInsensitiveDict, self).__contains__(self.__class__._k(key))
def has_key(self, key):
return super(CaseInsensitiveDict, self).has_key(self.__class__._k(key))
def pop(self, key, *args, **kwargs):
return super(CaseInsensitiveDict, self).pop(self.__class__._k(key), *args, **kwargs)
def get(self, key, *args, **kwargs):
return super(CaseInsensitiveDict, self).get(self.__class__._k(key), *args, **kwargs)
def setdefault(self, key, *args, **kwargs):
return super(CaseInsensitiveDict, self).setdefault(self.__class__._k(key), *args, **kwargs)
def update(self, E={}, **F):
super(CaseInsensitiveDict, self).update(self.__class__(E))
super(CaseInsensitiveDict, self).update(self.__class__(**F))
def _convert_keys(self):
for k in list(self.keys()):
v = super(CaseInsensitiveDict, self).pop(k)
self.__setitem__(k, v)
Si bien un diccionario que no distingue entre mayúsculas y minúsculas es una solución, y hay respuestas sobre cómo lograrlo, es posible que haya una forma más fácil en este caso. Una búsqueda de mayúsculas y minúsculas es suficiente:
import re
text = "Practice changing the Color"
words = {''color'': ''colour'', ''practice'': ''practise''}
def replace(words,text):
keys = words.keys()
for i in keys:
exp = re.compile(i, re.I)
text = re.sub(exp, words[i], text)
return text
text = replace(words,text)
print text
Si te entiendo correctamente y quieres una forma de teclear diccionarios de una manera que no distinga mayúsculas y minúsculas, una forma sería subclasificar dict y sobrecargar el establecedor / captador:
class CaseInsensitiveDict(dict):
def __setitem__(self, key, value):
super(CaseInsensitiveDict, self).__setitem__(key.lower(), value)
def __getitem__(self, key):
return super(CaseInsensitiveDict, self).__getitem__(key.lower())
Solo para que conste. Encontré una impresionante mejora en las Requests :
https://github.com/kennethreitz/requests/blob/v1.2.3/requests/structures.py#L37