Python 不区分大小写的字典

Python 不区分大小写的字典,python,Python,我希望我的字典不区分大小写 我有以下示例代码: 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 = "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
输出=练习改变颜色

我想要另一个字符串,
“练习更改颜色”
,(其中
颜色
以大写字母开头)也提供相同的输出

我相信有一种通用的方法可以使用
mydictionary[key.lower()]
但我不确定如何最好地将其集成到现有代码中。(无论如何,如果这是一种合理、简单的方法)。

如果我理解正确,并且您希望以不区分大小写的方式对字典进行键控,一种方法是将dict子类化并重载setter/getter:

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())

虽然不区分大小写的字典是一种解决方案,并且有解决方法,但在这种情况下可能有一种更简单的方法。不区分大小写的搜索就足够了:

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

你会考虑在输入和使用完全小写字典时使用<代码> String、LUVER()/<代码>吗?这是一个有点老套的解决方案,但它只是为了记录在案。我发现了一个很棒的宣传:


在我的特定实例中,我需要一个不区分大小写的查找,但是,我不想修改密钥的原始大小写。例如:

>>> d = {}
>>> d['MyConfig'] = 'value'
>>> d['myconfig'] = 'new_value'
>>> d
{'MyConfig': 'new_value'}
您可以看到字典仍然具有原始密钥,但是它可以不区分大小写地访问。以下是一个简单的解决方案:

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
获取和设置字典中的条目都需要_散列_uu和_eq uu覆盖。这是在创建键,如果它们大小写不敏感地相等,则将它们散列到字典中的相同位置

现在,创建一个自定义字典,使用提供的键初始化CaseInsensitiveKey:

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)
或者在使用字典时,只需确保始终将CaseInsensitiveKey的实例作为键传递。

不适用于大量的,因此它不能用作插入式dict替换。获得正确的
dict
替换时的一些技巧点:

  • 重载所有涉及键的方法
  • 正确处理非字符串键
  • 正确处理类的构造函数
以下几点应能更好地发挥作用:

类案例不敏感指令(dict):
@类方法
def_k(cls,钥匙):
如果isinstance(key,basestring)else key,则返回key.lower()
定义初始化(self,*args,**kwargs):
super(不区分大小写的指令,self)。\uuuuu init\uuuuuu(*args,**kwargs)
self.\u转换\u键()
def _u获取项目(自身,密钥):
返回super(不区分大小写的指令,self)。\uu获取项目\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu类\uuuuuuuuuk(键))
定义设置项(自身、键、值):
super(不区分大小写的指令,self)。\uuuuuu设置项\uuuuuuuuuu(self.\uuuuuu类\uuuuuu.\k(键),值)
def uu delitem uu(self,key):
返回super(不区分大小写,self)。\u delitem\u(self.\u class\u.\u k(键))
def___;包含_______;(自身,密钥):
返回super(不区分大小写的指令,self)。\uuuuu包含\uuuuu(self.\uuuu类\uuuu.\k(键))
def具有_键(自身,键):
return super(不区分大小写,self).has_key(self.\uuuu class.\uuu.\k(key))
def pop(自身、钥匙、*args、**kwargs):
返回super(不区分大小写,self).pop(self.\u class.\u.\u k(键),*args,**kwargs)
def get(自身、键、*args、**kwargs):
return super(不区分大小写,self).get(self.\u class.\u.\u k(键),*args,**kwargs)
def setdefault(自身、键、*args、**kwargs):
返回super(CaseInsensitiveDict,self).setdefault(self.\u class.\u.\u k(键),*args,**kwargs)
def更新(self,E={},**F):
超级(不区分大小写,self).更新(self.\uuuuuu类\uuuuuuuu(E))
超级(不区分大小写的指令,self).更新(self.\uuuuuuu class\uuuuu(**F))
定义转换键(自):
对于列表中的k(self.keys()):
v=super(不区分大小写,self).pop(k)
self.\uuuu设置项(k,v)
我修改了(谢谢!),使其更加紧凑、独立,并进行了一些小的更新,以允许从
{'a':1,'B':2}
和支持
\uuuuuuuuuu包含
协议进行构造。 最后,由于
CaseInsensitiveDict.Key
应该是字符串(还有什么可以区分大小写),因此从
str
派生
Key
类是一个好主意,例如,可以使用
json.dumps来转储
CaseInsensitiveDict

# 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)
下面是一个基本的测试脚本,供那些喜欢检查实际情况的人使用:

# 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()])

我刚刚设置了一个函数来处理这个问题:

def setLCdict(d, k, v):
    k = k.lower()
    d[k] = v
    return d

myDict = {}
所以不是

myDict['A'] = 1
myDict['B'] = 2
你可以:

myDict = setLCdict(myDict, 'A', 1)
myDict = setLCdict(myDict, 'B', 2)
然后,您可以在查找该值之前将其小写,也可以编写一个函数来执行此操作

    def lookupLCdict(d, k):
        k = k.lower()
        return d[k]

    myVal = lookupLCdict(myDict, 'a')

如果您希望在全局范围内执行此操作,则可能不太理想,但如果它只是您希望使用它的子集,则效果良好。

您可以使用一行代码执行dict键不区分大小写的搜索:

>>> input_dict = {'aBc':1, 'xyZ':2}
>>> search_string = 'ABC'
>>> next((value for key, value in input_dict.items() if key.lower()==search_string.lower()), None)
1
>>> search_string = 'EFG'
>>> next((value for key, value in input_dict.items() if key.lower()==search_string.lower()), None)
>>>

您可以将其放入函数中:


def get_case_insensitive_key_value(input_dict, key):
    return next((value for dict_key, value in input_dict.items() if dict_key.lower() == key.lower()), None)



请注意,只返回第一个匹配项。

如果您只需要在代码中执行一次(因此,不需要指向函数),处理此问题的最直接方法是:

lowercase_dict={key.lower():原始_dict}中(key,value)的值

我在这里假设所讨论的dict没有那么大——复制它可能是不雅的,但是如果它不是大的,它不会伤害任何东西


与@Fred的答案相比,这个方法的优点是(尽管它也可以)在不存在密钥的情况下产生与dict相同的结果:一个密钥错误。

是否也有一个特殊的内置函数调用“in”呢?下面是一个可能需要重载的方法的完整列表:setitem、getitem、contains、get、has\u key、pop、setdefault、,和更新。init和fromkeys也可能被重载,以确保字典被正确初始化。也许我错了,Python承诺get、hash_key、pop、setdefault、update和init将根据getitem、setitem和contains实现