python

时间:2017-03-30 15:25:22

标签: python string python-2.7 case-insensitive

我需要在集合和字典键中的python中执行不区分大小写的字符串比较。现在,创建不区分大小写的集合和字典子类证明非常棘手(请参阅:Case insensitive dictionary表示想法,请注意它们都使用较低 - 嘿,即使是被拒绝的PEP,尽管其范围很广有点宽广)。所以我创建了一个不区分大小写的字符串类(@AlexMartelli利用这个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中字符串比较的所有情况,但是我正在重构现有的代码,这些代码使用了一个更加笨重的类来进行字符串比较(内存和速度)无论如何使用lower() - 所以我可以在稍后阶段修改它 - 加上我在python 2上(如unicode所示)。我的问题是:

  • 我的操作员是否正确?

  • 这个类足以满足我的目的,因为我注意在dicts中构造键并将元素设置为CIstr个实例 - 我的目的是检查相等,包含,设置差异和类似操作。不区分大小写的方式。或者我错过了什么?

  • 是否值得缓存字符串的小写版本(例如,在这个古老的python配方中可以看到:Case Insensitive Strings)。这个comment表明不是 - 而且我希望尽可能快地构建并尽可能小,但人们似乎包含了这个。

感谢Python 3兼容性提示!

微小的演示:

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

2 个答案:

答案 0 :(得分:1)

代码大多看起来很好。我会删除__ge____le____ne__中的快捷方式,然后展开它们直接调用 lower()

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

答案 1 :(得分:1)

在您的演示中,您使用'a'查看集合中的内容。如果您尝试使用'A',则无效,因为'A'具有不同的哈希值。同样'A' in d.keys()也是如此,但'A' in d将是错误的。你实际上创建了一个违反所有哈希的正常契约的类型,声称它等于具有不同哈希值的对象。

您可以将此答案与有关创建专门的dicts的答案结合起来,并在尝试查找之前使用dict将任何可能的键转换为CIstr。然后,您的所有CIstr转换都可以隐藏在字典类中。

E.g。

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.

(基于https://stackoverflow.com/a/2082169/3890632