root/branches/add_stat_caching/ftpsync-0.1/casestr.py

Revision 545, 7.9 kB (checked in by schwa, 2 years ago)
Code contributed by Martin Wilck. (Thank you!) I might use some of
this code to add caching of stat results to ftputil.
  • Property svn:eol-style set to native
Line 
1 import sys
2 from types import IntType, StringType
3
4 class CaseInsStr(str):
5     """
6     A reimplementation of the standard string class 'str' which
7     behaves in a case insensitive manner.
8
9     See the python library documentation ("String methods") for
10     documentation of the methods.
11
12     The case-insensitivity is greedy, i.e. operations between 'str'
13     and 'CaseInsStr' objects return 'CaseInsStr' objects.
14     All methods inherited from 'str' which would normally return
15     'str' objects return 'CaseInsStr', including lower() and upper().
16
17     Use the str() method to convert to a normal, case-sensitive string.
18
19     The string itself is not converted to lower or upper case.
20 """
21
22     def cast(self, str):
23         """
24         Cast a "str" object into a "CaseInsStr" object.
25         """
26         return CaseInsStr(str)
27
28     def str(self):
29         """
30         Convert to case-sensitive 'str' object.
31         """
32         return self.__str__()
33
34     def _lower(self):
35         return str.lower(self)
36
37     def __cmp__(self, other):
38         """
39         "CaseInsStr" objects can be compared with each other or with strings.
40         Objects are compared case-insensitively.
41         
42 >>> Spam = CaseInsStr("Spam")
43 >>> print "egg" < Spam, Spam >= "egg", "egg" < Spam.str(), Spam == "spam"
44 True True False True
45 >>> phrase = [CaseInsStr("Eric"), "the", "half", "a", "Bee"]
46 >>> phrase.sort()
47 >>> print phrase
48 ['Bee', 'a', 'Eric', 'half', 'the']
49         """
50         ret = cmp(self._lower() , other.lower())
51         return ret
52
53     def __ne__(self, other):
54         return self.__cmp__(other) != 0
55
56     def __eq__(self, other):
57         return self.__cmp__(other) == 0
58
59     def __lt__(self, other):
60         return self.__cmp__(other) == -1
61
62     def __le__(self, other):
63         return self.__cmp__(other) != 1
64
65     def __gt__(self, other):
66         return self.__cmp__(other) == 1
67
68     def __ge__(self, other):
69         return self.__cmp__(other) != -1
70
71     def __getitem__(self, n):
72         return CaseInsStr(str.__getitem__(self, n))
73
74     def __getslice__(self, i, j):
75         return CaseInsStr(str.__getslice__(self, i, j))
76
77     def __add__(self, other):
78         """
79 >>> # concatenation
80 >>> print "The "+CaseInsStr("Lovely ")+"Spam" == "the LOVELY spam"
81 True
82 """
83         return CaseInsStr(str.__add__(self, other))
84
85     def __radd__(self, other):
86         return CaseInsStr(str.__add__(other, self))
87  
88     def __mul__(self, n):
89         """
90 >>> print 4 * CaseInsStr("Spam!") +  CaseInsStr("Egg!") * 3
91 Spam!Spam!Spam!Spam!Egg!Egg!Egg!
92 """
93         return CaseInsStr(str.__mul__(self, n))
94        
95     def __rmul__(self, n):
96         return CaseInsStr(str.__rmul__(self, n))
97
98     def center(self, width):
99         return CaseInsStr(str.center(self, width))
100        
101     def count(self, sub, *args, **kwargs):
102         """
103 >>> print CaseInsStr(4*"SPAM!").count("spam")
104 4
105 """
106         return self._lower().count(sub.lower(), *args, **kwargs)
107    
108     def find(self, other):
109         """
110 >>> Love = CaseInsStr("The Lovely Spam")
111 >>> print Love.find("spam"), Love.rfind("love"), Love.index("ELY")
112 11 4 7
113 """
114         return self._lower().find(other.lower())
115
116     def index(self, other):
117         return self._lower().index(other.lower())
118
119     def join(self, seq):
120         """
121 >>> print CaseInsStr("!").join(["spam", "Spam", "SPAM"])
122 spam!Spam!SPAM
123 >>> print CaseInsStr("!").join(["spam", "Spam", "SPAM"]).find("SPAM")
124 0
125 """
126         return CaseInsStr(str.join(self, seq))
127        
128     def ljust(self, width):
129         return CaseInsStr(str.ljust(self, width))
130
131     def replace(self, old, new, count=None):
132         """
133 >>> # replace
134 >>> print CaseInsStr(4*"EGG!").replace("egg", "Spam", 3)
135 Spam!Spam!Spam!EGG!
136 """
137         if count is not None and (type(count) != IntType or count < 0):
138             raise ValueError, count
139         old = old.lower()
140         lwr = self._lower()
141         n = 0
142         idx = 0
143         ret = ""
144        
145         while True:
146             i = lwr[idx:].find(old)
147             if i == -1 or (count is not None and n >= count):
148                 break
149             ret = ret + str.__getslice__(self, idx, idx+i) + new
150             n = n + 1
151             idx = idx + i + len(old)
152
153         ret = ret + str.__getslice__(self, idx, sys.maxint)
154         return CaseInsStr(ret)
155
156     def startswith(self, other):
157         return self._lower().startswith(other.lower())
158
159     def endswith(self, other):
160         return self._lower().endswith(other.lower())
161
162     def rfind(self, other):
163         return self._lower().rfind(other.lower())
164
165     def rindex(self, other):
166         return self._lower().rindex(other.lower())
167
168     def rjust(self, width):
169         return CaseInsStr(str.rjust(self, width))
170
171     def split(self, sep=None, maxsplit=0):
172         """
173 >>> print CaseInsStr("Fiddle de dum, fiddle de dee").split("DE", 2)
174 ['Fiddle ', ' dum, fiddle ', ' dee']
175 """
176         if sep is None:
177             return self.__str__().split(sep, maxsplit)
178
179         if type(maxsplit) != IntType:
180             raise TypeError, maxsplit
181         if maxsplit < 0:
182             raise ValueError, maxsplit
183
184         ret = []
185         last = 0
186         while True:
187             i = self[last:].find(sep)
188             if i == -1 or (maxsplit > 0 and len(ret) == maxsplit):
189                 break
190             ret = ret + [self[last:last+i]]
191             last = last + i + len(sep)
192        
193         ret = ret + [self[last:]]
194         return ret
195
196     def rsplit(self, sep=None, maxsplit=0):
197         """
198 >>> print CaseInsStr("spam and eggs AND bees And knights").rsplit("and", 2)
199 ['spam and eggs ', ' bees ', ' knights']
200 """
201         if sep is None:
202             return self.__str__().rsplit(sep, maxsplit)
203
204         if type(maxsplit) != IntType:
205             raise TypeError, maxsplit
206         if maxsplit < 0:
207             raise ValueError, maxsplit
208
209         ret = []
210         last = sys.maxint
211         while True:
212             i = self[:last].rfind(sep)
213             if i == -1 or (maxsplit > 0 and len(ret) == maxsplit):
214                 break
215             ret = [self[i+len(sep):last]] + ret
216             last = i
217        
218         ret = [self[:last]] + ret
219         return ret
220
221     def splitlines(self, keepends=None):
222         return [CaseInsStr(x)
223                 for x in str.splitlines(self, keepends)]
224
225     def _stripchars(self, ch):
226         if type(ch) is not StringType:
227             raise TypeError, ch
228         s = ""
229         for x in ch:
230             if x.isalpha():
231                 u = x.upper()
232                 l = x.lower()
233                 if l != u:
234                     s = s + l + u
235                     continue
236             s = s + x
237         return s
238
239     def strip(self, *chars):
240         """
241         Stripped characters are case-insensitive:
242 >>> print CaseInsStr(" Spam and eggs ").strip("s ")
243 pam and egg
244 >>> print "'%s'" % CaseInsStr("  a  ").lstrip()
245 'a  '
246 """
247         if chars is () or chars[0] is None:
248             return CaseInsStr(str.strip(self))
249         else:
250             return CaseInsStr(str.strip(self, self._stripchars(chars[0])))
251
252     def lstrip(self, *chars):
253         if chars is () or chars[0] is None:
254             return CaseInsStr(str.lstrip(self))
255         else:
256             return CaseInsStr(str.lstrip(self, self._stripchars(chars[0])))
257
258     def rstrip(self, *chars):
259         if chars is () or chars[0] is None:
260             return CaseInsStr(str.rstrip(self))
261         else:
262             return CaseInsStr(str.rstrip(self, self._stripchars(chars[0])))
263
264     def swapcase(self):
265         return CaseInsStr(str.swapcase(self))
266
267     def title(self):
268         return CaseInsStr(str.title(self))
269    
270     def translate(self):
271         raise NotImplementedError, "translate() method not implemented"
272
273     def lower(self):
274         """
275 >>> Spam = CaseInsStr("Spam")
276 >>> print Spam.lower(), Spam.upper(), Spam.lower() == "SPAM", Spam.upper() == "spam"
277 spam SPAM True True
278 """
279         return CaseInsStr(self._lower())
280
281     def upper(self):
282         return CaseInsStr(self.__str__().upper())
283    
284     def zfill(self, width):
285         return CaseInsStr(str.zfill(self, width))
286
287 def _test():
288     import doctest, casestr
289     doctest.testmod(casestr)
290
291 if __name__ == "__main__":
292     _test()
Note: See TracBrowser for help on using the browser.