Welcome, guest | Sign In | My Account | Store | Cart

This is a class you use in place of a string and it emulates a string in all practical ways except that comparisons and lookups are case insensitive. All uses of the string for assignments, however, yield the original case.

Python, 61 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
class iStr(str):
    """Case insensitive strings class.
    Performs like str except comparisons are case insensitive."""

    def __init__(self, strMe):
        str.__init__(self, strMe)
        self.__lowerCaseMe = strMe.lower()

    def __repr__(self):
        return "iStr(%s)" % str.__repr__(self)

    def __eq__(self, other):
        return self.__lowerCaseMe == other.lower()

    def __lt__(self, other):
        return self.__lowerCaseMe < other.lower()

    def __le__(self, other):
        return self.__lowerCaseMe <= other.lower()

    def __gt__(self, other):
        return self.__lowerCaseMe > other.lower()

    def __ne__(self, other):
        return self.__lowerCaseMe != other.lower()

    def __ge__(self, other):
        return self.__lowerCaseMe >= other.lower()

    def __cmp__(self, other):
        return cmp(self.__lowerCaseMe, other.lower())

    def __hash__(self):
        return hash(self.__lowerCaseMe)

    def __contains__(self, other):
        return other.lower() in self.__lowerCaseMe

    def count(self, other, *args):
        return str.count(self.__lowerCaseMe, other.lower(), *args)

    def endswith(self, other, *args):
        return str.endswith(self.__lowerCaseMe, other.lower(), *args)

    def find(self, other, *args):
        return str.find(self.__lowerCaseMe, other.lower(), *args)
    
    def index(self, other, *args):
        return str.index(self.__lowerCaseMe, other.lower(), *args)

    def lower(self):   # Courtesy Duncan Booth
        return self.__lowerCaseMe

    def rfind(self, other, *args):
        return str.rfind(self.__lowerCaseMe, other.lower(), *args)

    def rindex(self, other, *args):
        return str.rindex(self.__lowerCaseMe, other.lower(), *args)

    def startswith(self, other, *args):
        return str.startswith(self.__lowerCaseMe, other.lower(), *args)

    

We've found this very handy when using strings as dictionary indices or when searching for Windows filenames in lists.

Some examples:

>>> poem = iStr("Mary had a little LAMB")
>>> poem == "mary had a little lamb"
1
>>> poem.find("LITTLE")
11
>>> poem.title()
'Mary Had A Little Lamb'
>>> poem
iStr('Mary had a little LAMB')
>>>

Note that the hash value is the lower case value. If you use an iStr as a dictionary index, you will need to make sure that lookups are lower case too:

>>> filelist = {iStr('WINNT'): 0, iStr('Temp'): 0}
>>> 'winnt' in filelist
1
>>> 'WINNT' in filelist
0
>>> 'temp' in filelist
1
>>>

The replace() method of the str class hasn't been tackled. If you use replace on an iStr, it will operate as on a normal string.

2 comments

Mark Mc Mahon 17 years, 6 months ago  # | flag

Make less restrictive to be more like python strings. It is quite possible in python to compare strings against integers or other non strings. So in __cmp__ and __eq__ I have added a try:except block around the current line, and in the except part put the same line but without the call to lower() (as it is this that raises the exception). e.g.

def __cmp__(self, other):
   try:
        return cmp(self.__lowerCaseMe, other.lower())
   except:
        return cmp(self.__lowerCaseMe, other)
Jason Orendorff 15 years, 9 months ago  # | flag

Terrible idea. Use a case-insensitive dictionary instead.

Created by Dale Strickland-Clark on Wed, 16 Apr 2003 (PSF)
Python recipes (4591)
Dale Strickland-Clark's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks