不区分大小写的字典

2025-04-16 08:56:00
admin
原创
22
摘要:问题描述:我希望我的字典不区分大小写。我有这个示例代码:text = "practice changing the color" words = {'color': 'colour', 'practice': 'practise'} def replace(words,...

问题描述:

我希望我的字典不区分大小写。

我有这个示例代码:

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

输出=练习改变颜色

我希望另一个字符串,"practice changing the Color"Color以大写字母开头)也能给出相同的输出。

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


解决方案 1:

仅供记录。我发现一个很棒的Requests实现:

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

解决方案 2:

目前接受的答案在很多情况下都行不通,所以不能直接用作替代方案dict。获取合适的替代方案需要注意以下几点dict

  • 重载所有涉及键的方法

  • 正确处理非字符串键

  • 正确处理类的构造函数

下面的应该效果会更好:

class CaseInsensitiveDict(dict):
    @classmethod
    def _k(cls, key):
        return key.lower() if isinstance(key, str) 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)

解决方案 3:

如果我理解正确的话,你想要一种以不区分大小写的方式键入字典的方法,一种方法是将 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())

解决方案 4:

在我的特定情况下,我需要不区分大小写的查找,但我不想修改键的原始大小写。例如:

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

获取和设置字典中的条目时都需要覆盖 hasheq 。这将创建键,如果它们大小写不敏感地相等,则它们哈希到字典中的相同位置。

现在创建一个自定义字典,使用提供的键初始化 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 的实例作为键。

解决方案 5:

你会考虑string.lower()在输入中使用完全小写的字典吗?这有点 hacky,但确实有效。

解决方案 6:

我修改了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)

对于那些喜欢检查实际操作的人来说,这是一个基本的测试脚本:

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

解决方案 7:

您可以使用一行代码进行 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)


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

解决方案 8:

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

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

解决方案 9:

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

lowercase_dict = {key.lower():original_dict 中 (key, value) 的值}

我在这里假设所讨论的字典并不是那么大——复制它可能不太雅致,但如果它不大,就不会造成任何损害。

与@Fred 的答案相比,这个答案的优势在于(尽管它也有效),当键不存在时,它会产生与字典相同的结果:KeyError。

解决方案 10:

解决这个问题的方法有很多,每种方法都有其优缺点。补充一下(好像没有提到这个选项),可以扩展str类并将其用作键:

class CaseInsensitiveStr(str):
    def __hash__(self) -> 'int':
        return hash(self.lower())
    def __eq__(self, other:'str') -> 'bool':
        return self.lower() == other.lower()

如果所讨论的字典是私有的并且使用某种接口来访问它,它可以很好地工作。

class MyThing:
    def __init__(self):
        self._d: 'dict[CaseInsensitiveStr, int]' = dict()
    def set(self, key:'str', value:'int'):
        self._d[CaseInsensitiveStr(key)] = value
    def get(self, key:'str') -> 'int':
        return self._d[CaseInsensitiveStr(key)]

解决方案 11:

来源:基于@m000的回答。以下变体提供了一个 get_orig_key 方法,通过跟踪上一个“set”操作的区分大小写的键。

class RobbieCaseInsensitiveDict(dict):
    @classmethod
    def _k(cls, key):
        return key.lower() if isinstance(key, str) else key

    def __init__(self, *args, **kwargs):
        super(RobbieCaseInsensitiveDict, self).__init__(*args, **kwargs)
        self.key_dict = {}
        for key in self.keys():
            if isinstance(key, str):
                self.key_dict[key.lower()] = key
        self._convert_keys()

    def get_orig_key(self, case_ins_key):
        if case_ins_key in self.key_dict:
            return self.key_dict[case_ins_key]
        else:
            return case_ins_key

    def __getitem__(self, key):
        return super(RobbieCaseInsensitiveDict, self).__getitem__(self.__class__._k(key))

    def __setitem__(self, key, value):
        if isinstance(key, str):
            self.key_dict[key.lower()] = key
        super(RobbieCaseInsensitiveDict, self).__setitem__(self.__class__._k(key), value)

    def __delitem__(self, key):
        return super(RobbieCaseInsensitiveDict, self).__delitem__(self.__class__._k(key))

    def __contains__(self, key):
        return super(RobbieCaseInsensitiveDict, self).__contains__(self.__class__._k(key))

    def has_key(self, key):
        return super(RobbieCaseInsensitiveDict, self).has_key(self.__class__._k(key))

    def pop(self, key, *args, **kwargs):
        return super(RobbieCaseInsensitiveDict, self).pop(self.__class__._k(key), *args, **kwargs)

    def get(self, key, *args, **kwargs):
        return super(RobbieCaseInsensitiveDict, self).get(self.__class__._k(key), *args, **kwargs)

    def setdefault(self, key, *args, **kwargs):
        if isintance(key, str):
            self.key_dict[key.lower()] = key
        return super(RobbieCaseInsensitiveDict, self).setdefault(self.__class__._k(key), *args, **kwargs)

    def update(self, E={}, **F):
        super(RobbieCaseInsensitiveDict, self).update(self.__class__(E))
        super(RobbieCaseInsensitiveDict, self).update(self.__class__(**F))

    def _convert_keys(self):
        for k in list(self.keys()):
            v = super(RobbieCaseInsensitiveDict, self).pop(k)
            self.__setitem__(k, v)

解决方案 12:

这是一个简单且正确的实现,兼容 Python 3。希望它足够简单,能够被人类理解。其他答案仍然尝试与 Python 2 兼容。

from collections.abc import Mapping


class CaseInsensitiveDict(dict):

    def __init__(self, data=None, **kwargs):
        self.update(data, **kwargs)

    def get(self, k, default=None):
        return super().get(k.lower(), default)

    def pop(self, k):
        return super().pop(k.lower())

    def setdefault(self, k, default=None):
        return super().setdefault(k.lower(), default)

    def update(self, data=None, **kwargs):
        if data is not None:
            if isinstance(data, Mapping):
                data = data.items()
            super().update((k.lower(), v) for k, v in data)
        super().update((k.lower(), v) for k, v in kwargs)

    def __contains__(self, k):
        return super().__contains__(k.lower())

    def __delitem__(self, k):
        super().__delitem__(k.lower())

    def __eq__(self, other):
        if not isinstance(other, Mapping):
            return False
        if not isinstance(other, CaseInsensitiveDict):
            other = CaseInsensitiveDict(other)
        return super().__eq__(other)

    def __getitem__(self, k):
        return super().__getitem__(k.lower())

    def __setitem__(self, k, v):
        super().__setitem__(k.lower(), v)

解决方案 13:

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

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

如果您想在全球范围内执行此操作,这可能不是理想的选择,但如果您希望将其用于一个子集,那么效果很好。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   2482  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1533  
  PLM(产品生命周期管理)项目对于企业优化产品研发流程、提升产品质量以及增强市场竞争力具有至关重要的意义。然而,在项目推进过程中,范围蔓延是一个常见且棘手的问题,它可能导致项目进度延迟、成本超支以及质量下降等一系列不良后果。因此,有效避免PLM项目范围蔓延成为项目成功的关键因素之一。以下将详细阐述三大管控策略,助力企业...
plm系统   0  
  PLM(产品生命周期管理)项目管理在企业产品研发与管理过程中扮演着至关重要的角色。随着市场竞争的加剧和产品复杂度的提升,PLM项目面临着诸多风险。准确量化风险优先级并采取有效措施应对,是确保项目成功的关键。五维评估矩阵作为一种有效的风险评估工具,能帮助项目管理者全面、系统地评估风险,为决策提供有力支持。五维评估矩阵概述...
免费plm软件   0  
  引言PLM(产品生命周期管理)开发流程对于企业产品的全生命周期管控至关重要。它涵盖了从产品概念设计到退役的各个阶段,直接影响着产品质量、开发周期以及企业的市场竞争力。在当今快速发展的科技环境下,客户对产品质量的要求日益提高,市场竞争也愈发激烈,这就使得优化PLM开发流程成为企业的必然选择。缺陷管理工具和六西格玛方法作为...
plm产品全生命周期管理   0  
热门文章
项目管理软件有哪些?
曾咪二维码

扫码咨询,免费领取项目管理大礼包!

云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用