python 中的不区分大小写的字符串 class

A case insensitive string class in python

我需要在 python 中的集合和字典键中执行不区分大小写的字符串比较。现在,要创建不区分大小写的集合和 dict subclasses 证明非常棘手(请参阅:@AlexMartelli 的 Case insensitive dictionary for ideas, note they all use lower - hey there's even a rejected PEP, albeit its scope is a bit broader). So I went with creating a case insensitive string class (leveraging this answer):

class CIstr(unicode):
    """Case insensitive with respect to hashes and comparisons string class"""

    #--Hash/Compare
    def __hash__(self):
        return hash(self.lower())
    def __eq__(self, other):
        if isinstance(other, basestring):
            return self.lower() == other.lower()
        return NotImplemented
    def __ne__(self, other): return not (self == other)
    def __lt__(self, other):
        if isinstance(other, basestring):
            return self.lower() < other.lower()
        return NotImplemented
    def __ge__(self, other): return not (self < other)
    def __gt__(self, other):
        if isinstance(other, basestring):
            return self.lower() > other.lower()
        return NotImplemented
    def __le__(self, other): return not (self > other)

我完全知道 lowernot really enough 以涵盖 unicode 中字符串比较的所有情况,但我正在重构现有代码,这些代码使用更笨重的 class 进行字符串比较(内存和速度方面)无论如何使用 lower() - 所以我可以在稍后阶段修改它 - 而且我在 python 2(如 unicode 所见)。我的问题是:

Python 感谢 3 个兼容性提示!

小型演示:

d = {CIstr('A'): 1, CIstr('B'): 2}
print 'a' in d # True
s = set(d)
print {'a'} - s # set([])

大部分代码看起来都不错。我会删除 __ge____le____ne__ 中的快捷方式,并将它们扩展为直接调用 lower()

这个快捷方式看起来像在`functools.total_ordering() 中所做的,但它只会减慢代码速度并使测试跨类型比较变得更加困难当方法相互依赖时,很难做到正确。

在您的演示中,您正在使用 'a' 在您的集合中查找内容。如果您尝试使用 'A',它将不起作用,因为 'A' 具有不同的哈希值。 'A' in d.keys() 也为真,但 'A' in d 为假。通过声称等于具有不同哈希值的对象,您实际上已经创建了一种违反所有哈希值的正常契约的类型。

您可以将此答案与有关创建专用字典的答案结合起来,并在尝试查找之前将任何可能的键转换为 CIstr 的字典。那么你所有的 CIstr 转换都可以隐藏在字典 class.

例如

class CaseInsensitiveDict(dict):
    def __setitem__(self, key, value):
        super(CaseInsensitiveDict, self).__setitem__(convert_to_cistr(key), value)
    def __getitem__(self, key):
        return super(CaseInsensitiveDict, self).__getitem__(convert_to_cistr(key))
    # __init__, __contains__ etc.

(基于)