不区分大小写的字典

Kim*_*Kim 64 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 = replace(words,text)

print text
Run Code Online (Sandbox Code Playgroud)

输出=练习改变颜色

我想要另一个字符串,"practice changing the Color"(Color以一个大写字母开头)也给出相同的输出.

我相信有一种通用的方法可以转换为小写, mydictionary[key.lower()]但我不知道如何最好地将它集成到我现有的代码中.(如果这是一个合理,简单的方法,无论如何).

m00*_*000 52

目前已批准的答案不适合工作,很多情况下,所以它不能被用来作为一个下拉dict更换.获得适当dict替换的一些棘手要点:

  • 重载涉及键的所有方法
  • 正确处理非字符串键
  • 正确处理类的构造函数

以下应该会更好:

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)
Run Code Online (Sandbox Code Playgroud)

  • 他们说,Python很容易.他们说,Python很有趣. (10认同)
  • 在python 3中,删除了抽象类型`basestring`.`str`可以用作替代品. (6认同)
  • @rr-。公平地说,想象一下在 C 中这样做。 (3认同)
  • 这很好,但有一个小问题.`update`的超级定义是`update(self,E = None,**F)`,意思是'E`是可选的.你已经重新定义它以使'E`成为必需.添加`= None`,这将是完美的. (2认同)

san*_*lto 47

仅供记录.我在Requests上发现了一个很棒的命令:

https://github.com/kennethreitz/requests/blob/v1.2.3/requests/structures.py#L37

  • `from requests.structures import CaseInsensitiveDict` (9认同)
  • @santiagobasulto - 这是“愚蠢的”,直到(需要工作/截止日期之前的时间)比率达到无穷大 (4认同)
  • 这可能有用,但是如果您需要的只是一个Case Insensitive Dict,那么将请求添加为依赖项就很愚蠢了. (3认同)

jkp*_*jkp 40

如果我理解正确并且你想要一种以非区分大小写的方式键入字典的方法,一种方法是子类化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())
Run Code Online (Sandbox Code Playgroud)

  • 这里是一个可能需要重载方法的完整列表:__setitem__,__getitem__,__contains__,获取对象的has_key,流行,setdefault和更新.__init__和fromkeys也应该重载,以确保字典正确初始化.也许我错了,在某些地方Python承诺get,hash_key,pop,setdefault,update和__init__将以__getitem __,__ setitem__和__contains__的形式实现,如果它们已经超载,但我不这么认为. (23认同)
  • 这个解决方案非常有限,因为它不适用于`dict`的常见用途.**不要在你的代码中使用它 - 除了最简单的用途之外它会破坏所有.**显然@MichaelMerchant试图添加缺失的东西,但是审核不同意改变了(同样的事情发生在我身上).我添加了一个新的答案,应该可以用作插入式"dict"替换[这里](http://stackoverflow.com/a/32888599/277172). (5认同)
  • 自从我最终编写代码后添加了`__contains __,get和has_key`给答案:) (4认同)
  • 子类化 `UserDict` 比 `dict` 更好 https://docs.python.org/3.5/library/collections.html#userdict-objects (2认同)

ple*_*con 11

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

>>> d = {}
>>> d['MyConfig'] = 'value'
>>> d['myconfig'] = 'new_value'
>>> d
{'MyConfig': 'new_value'}
Run Code Online (Sandbox Code Playgroud)

您可以看到字典仍然具有原始密钥,但是它不受大小写的影响.这是一个简单的解决方案:

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
Run Code Online (Sandbox Code Playgroud)

在字典中获取和设置条目都需要__hash__和__eq__覆盖.这是创建键,如果它们不区分大小写,则散列到字典中的相同位置.

现在要么创建一个自定义词典,使用提供的键初始化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)
Run Code Online (Sandbox Code Playgroud)

或者只是确保在使用字典时始终将CaseInsensitiveKey的实例作为键传递.

  • 您应该使用 `.casefold()` 而不是 `.lower()` 进行比较,`self.key.casefold() == other.key.casefold()`,以允许 `"ß"` 和 `"ss “` 等价于真实。 (3认同)

ins*_*get 10

您会考虑使用string.lower()输入并使用完全小写字典吗?这是一个hacky解决方案,但它的工作原理

  • 除非您想在第一次设置密钥时保留原始大小写,否则这很好. (4认同)
  • 使用 string.casefold() 代替 (3认同)
  • @ErikAronesty 文档链接:https://docs.python.org/library/stdtypes.html#str.casefold (2认同)

mlo*_*kot 5

我已经修改了pleasemorebacon简单但很好的解决方案(谢谢!),使其更加紧凑、独立,并进行了少量更新以允许构建{'a':1, 'B':2}和支持__contains__协议。最后,由于CaseInsensitiveDict.Key预计将字符串(还有什么可以区分大小写或没有),这是一个好主意,派生Key从类str的话,那是可能的,例如,转储CaseInsensitiveDictjson.dumps开箱。

# 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)
Run Code Online (Sandbox Code Playgroud)

这是一个基本的测试脚本,适合那些喜欢检查实际情况的人:

# 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()])
Run Code Online (Sandbox Code Playgroud)

  • 您应该使用 `.casefold()` 而不是 `.lower()` 进行比较,`self.casefold() == other.key.casefold()` 和 `hash(self.casefold())`,以允许其中“ß”和“ss”等同于 true。 (2认同)