Case insensitive dictionary?

Jason Mobarak jason at __no_spam__mobarak.name
Sat Jun 26 07:40:23 CEST 2004


Elbert Lev wrote:
> Hi!
> 
> Here is the problem:
> 
> I have a dictionary. Keys are strings. How to make dictionary  lookup
> case insensitive?
> 
> In other words:
> If dict = {'First":"Bob", "Last":"Tom"}, dict["first"] should return
> "Bob"
> 
> Maybe dictionary is not the right data type? If so what is?

"""
More or less complete, you might want to add some more tests...
"""

import UserDict
import sys
import traceback

class CaseInsensitiveDict (dict, UserDict.UserDict, UserDict.DictMixin):

     def __init__ (self, init=None, **kw):

         if init is not None:
             return super(CaseInsensitiveDict, 
self).__init__(self.lowerDict(init), **kw)

         return super(CaseInsensitiveDict, self).__init__(**kw)

     def ifStrKey (cls, key):

         if hasattr(key, 'lower'):
             return key.lower()

         return key

     ifStrKey = classmethod(ifStrKey)

     def lowerDict (cls, d):

         # this handle's the case were d is a "mapping type"
         # like (('foo','oof'), ('baz', 'zab'))
         d = dict(d)
         return dict([(k.lower(), v.lower()) for k in d.keys() for v in 
d.values()])

     lowerDict = classmethod(lowerDict)

     def __contains__ (self, key):
         return super(CaseInsensitiveDict, 
self).__contains__(self.ifStrKey(key))

     def get (self, key, default=None):
         return super(CaseInsensitiveDict, self).get(self.ifStrKey(key), 
default=default)

     def pop (self, key, *args):
         return super(CaseInsensitiveDict, self).pop(self.ifStrKey(key), 
*args)

     def setdefault (self, key, default):
         return super(CaseInsensitiveDict, self).pop(self.ifStrKey(key), 
default)

     def __delitem__ (self, key):
         return super(CaseInsensitiveDict, 
self).__delitem__(self.ifStrKey(key))

     def __getitem__ (self, key):
         return super(CaseInsensitiveDict, 
self).__getitem__(self.ifStrKey(key))

     def __setitem__ (self, key, item):
         return super(CaseInsensitiveDict, 
self).__setitem__(self.ifStrKey(key), item)

     def has_key (self, key):
         return super(CaseInsensitiveDict, 
self).has_key(self.ifStrKey(key))

     def update (self, d):
         return super(CaseInsensitiveDict, self).update(self.lowerDict(d))

def print_tb (e):

     e_fmt = traceback.format_exception(e.__class__, e, sys.exc_traceback)
     sys.stderr.write(''.join(e_fmt))
     print

def test_d (d, k):

     print `d`
     print 'Key', `k`

     try:
         val = `d[k]`
         print 'Value', val

     except KeyError, e:

         print 'Key failed'
         print_tb(e)

     print

if __name__ == '__main__':

     td = {'FOO':'bar'}


     d = CaseInsensitiveDict(td)
     test_d(d, 'FOO')

     d = CaseInsensitiveDict()
     d.update(td)
     test_d(d, 'FOO')

     try:
         # this should fail
         d = CaseInsensitiveDict((('foo', 'oof',), ('zab',)))
     except Exception, e:
         print_tb(e)

     d = CaseInsensitiveDict((('foo', 'oof',), ('zab', 'baz',)))
     test_d(d, 'FOO')
     d[object()] = 'bar'
     print `d`



More information about the Python-list mailing list