|
1 #!/usr/bin/env python |
|
2 ## vim:ts=4:et:nowrap |
|
3 """A user-defined wrapper around string objects |
|
4 |
|
5 Note: string objects have grown methods in Python 1.6 |
|
6 This module requires Python 1.6 or later. |
|
7 """ |
|
8 import sys |
|
9 |
|
10 __all__ = ["UserString","MutableString"] |
|
11 |
|
12 class UserString: |
|
13 def __init__(self, seq): |
|
14 if isinstance(seq, basestring): |
|
15 self.data = seq |
|
16 elif isinstance(seq, UserString): |
|
17 self.data = seq.data[:] |
|
18 else: |
|
19 self.data = str(seq) |
|
20 def __str__(self): return str(self.data) |
|
21 def __repr__(self): return repr(self.data) |
|
22 def __int__(self): return int(self.data) |
|
23 def __long__(self): return long(self.data) |
|
24 def __float__(self): return float(self.data) |
|
25 def __complex__(self): return complex(self.data) |
|
26 def __hash__(self): return hash(self.data) |
|
27 |
|
28 def __cmp__(self, string): |
|
29 if isinstance(string, UserString): |
|
30 return cmp(self.data, string.data) |
|
31 else: |
|
32 return cmp(self.data, string) |
|
33 def __contains__(self, char): |
|
34 return char in self.data |
|
35 |
|
36 def __len__(self): return len(self.data) |
|
37 def __getitem__(self, index): return self.__class__(self.data[index]) |
|
38 def __getslice__(self, start, end): |
|
39 start = max(start, 0); end = max(end, 0) |
|
40 return self.__class__(self.data[start:end]) |
|
41 |
|
42 def __add__(self, other): |
|
43 if isinstance(other, UserString): |
|
44 return self.__class__(self.data + other.data) |
|
45 elif isinstance(other, basestring): |
|
46 return self.__class__(self.data + other) |
|
47 else: |
|
48 return self.__class__(self.data + str(other)) |
|
49 def __radd__(self, other): |
|
50 if isinstance(other, basestring): |
|
51 return self.__class__(other + self.data) |
|
52 else: |
|
53 return self.__class__(str(other) + self.data) |
|
54 def __mul__(self, n): |
|
55 return self.__class__(self.data*n) |
|
56 __rmul__ = __mul__ |
|
57 def __mod__(self, args): |
|
58 return self.__class__(self.data % args) |
|
59 |
|
60 # the following methods are defined in alphabetical order: |
|
61 def capitalize(self): return self.__class__(self.data.capitalize()) |
|
62 def center(self, width, *args): |
|
63 return self.__class__(self.data.center(width, *args)) |
|
64 def count(self, sub, start=0, end=sys.maxint): |
|
65 return self.data.count(sub, start, end) |
|
66 def decode(self, encoding=None, errors=None): # XXX improve this? |
|
67 if encoding: |
|
68 if errors: |
|
69 return self.__class__(self.data.decode(encoding, errors)) |
|
70 else: |
|
71 return self.__class__(self.data.decode(encoding)) |
|
72 else: |
|
73 return self.__class__(self.data.decode()) |
|
74 def encode(self, encoding=None, errors=None): # XXX improve this? |
|
75 if encoding: |
|
76 if errors: |
|
77 return self.__class__(self.data.encode(encoding, errors)) |
|
78 else: |
|
79 return self.__class__(self.data.encode(encoding)) |
|
80 else: |
|
81 return self.__class__(self.data.encode()) |
|
82 def endswith(self, suffix, start=0, end=sys.maxint): |
|
83 return self.data.endswith(suffix, start, end) |
|
84 def expandtabs(self, tabsize=8): |
|
85 return self.__class__(self.data.expandtabs(tabsize)) |
|
86 def find(self, sub, start=0, end=sys.maxint): |
|
87 return self.data.find(sub, start, end) |
|
88 def index(self, sub, start=0, end=sys.maxint): |
|
89 return self.data.index(sub, start, end) |
|
90 def isalpha(self): return self.data.isalpha() |
|
91 def isalnum(self): return self.data.isalnum() |
|
92 def isdecimal(self): return self.data.isdecimal() |
|
93 def isdigit(self): return self.data.isdigit() |
|
94 def islower(self): return self.data.islower() |
|
95 def isnumeric(self): return self.data.isnumeric() |
|
96 def isspace(self): return self.data.isspace() |
|
97 def istitle(self): return self.data.istitle() |
|
98 def isupper(self): return self.data.isupper() |
|
99 def join(self, seq): return self.data.join(seq) |
|
100 def ljust(self, width, *args): |
|
101 return self.__class__(self.data.ljust(width, *args)) |
|
102 def lower(self): return self.__class__(self.data.lower()) |
|
103 def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars)) |
|
104 def partition(self, sep): |
|
105 return self.data.partition(sep) |
|
106 def replace(self, old, new, maxsplit=-1): |
|
107 return self.__class__(self.data.replace(old, new, maxsplit)) |
|
108 def rfind(self, sub, start=0, end=sys.maxint): |
|
109 return self.data.rfind(sub, start, end) |
|
110 def rindex(self, sub, start=0, end=sys.maxint): |
|
111 return self.data.rindex(sub, start, end) |
|
112 def rjust(self, width, *args): |
|
113 return self.__class__(self.data.rjust(width, *args)) |
|
114 def rpartition(self, sep): |
|
115 return self.data.rpartition(sep) |
|
116 def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars)) |
|
117 def split(self, sep=None, maxsplit=-1): |
|
118 return self.data.split(sep, maxsplit) |
|
119 def rsplit(self, sep=None, maxsplit=-1): |
|
120 return self.data.rsplit(sep, maxsplit) |
|
121 def splitlines(self, keepends=0): return self.data.splitlines(keepends) |
|
122 def startswith(self, prefix, start=0, end=sys.maxint): |
|
123 return self.data.startswith(prefix, start, end) |
|
124 def strip(self, chars=None): return self.__class__(self.data.strip(chars)) |
|
125 def swapcase(self): return self.__class__(self.data.swapcase()) |
|
126 def title(self): return self.__class__(self.data.title()) |
|
127 def translate(self, *args): |
|
128 return self.__class__(self.data.translate(*args)) |
|
129 def upper(self): return self.__class__(self.data.upper()) |
|
130 def zfill(self, width): return self.__class__(self.data.zfill(width)) |
|
131 |
|
132 class MutableString(UserString): |
|
133 """mutable string objects |
|
134 |
|
135 Python strings are immutable objects. This has the advantage, that |
|
136 strings may be used as dictionary keys. If this property isn't needed |
|
137 and you insist on changing string values in place instead, you may cheat |
|
138 and use MutableString. |
|
139 |
|
140 But the purpose of this class is an educational one: to prevent |
|
141 people from inventing their own mutable string class derived |
|
142 from UserString and than forget thereby to remove (override) the |
|
143 __hash__ method inherited from UserString. This would lead to |
|
144 errors that would be very hard to track down. |
|
145 |
|
146 A faster and better solution is to rewrite your program using lists.""" |
|
147 def __init__(self, string=""): |
|
148 self.data = string |
|
149 def __hash__(self): |
|
150 raise TypeError, "unhashable type (it is mutable)" |
|
151 def __setitem__(self, index, sub): |
|
152 if index < 0: |
|
153 index += len(self.data) |
|
154 if index < 0 or index >= len(self.data): raise IndexError |
|
155 self.data = self.data[:index] + sub + self.data[index+1:] |
|
156 def __delitem__(self, index): |
|
157 if index < 0: |
|
158 index += len(self.data) |
|
159 if index < 0 or index >= len(self.data): raise IndexError |
|
160 self.data = self.data[:index] + self.data[index+1:] |
|
161 def __setslice__(self, start, end, sub): |
|
162 start = max(start, 0); end = max(end, 0) |
|
163 if isinstance(sub, UserString): |
|
164 self.data = self.data[:start]+sub.data+self.data[end:] |
|
165 elif isinstance(sub, basestring): |
|
166 self.data = self.data[:start]+sub+self.data[end:] |
|
167 else: |
|
168 self.data = self.data[:start]+str(sub)+self.data[end:] |
|
169 def __delslice__(self, start, end): |
|
170 start = max(start, 0); end = max(end, 0) |
|
171 self.data = self.data[:start] + self.data[end:] |
|
172 def immutable(self): |
|
173 return UserString(self.data) |
|
174 def __iadd__(self, other): |
|
175 if isinstance(other, UserString): |
|
176 self.data += other.data |
|
177 elif isinstance(other, basestring): |
|
178 self.data += other |
|
179 else: |
|
180 self.data += str(other) |
|
181 return self |
|
182 def __imul__(self, n): |
|
183 self.data *= n |
|
184 return self |
|
185 |
|
186 if __name__ == "__main__": |
|
187 # execute the regression test to stdout, if called as a script: |
|
188 import os |
|
189 called_in_dir, called_as = os.path.split(sys.argv[0]) |
|
190 called_as, py = os.path.splitext(called_as) |
|
191 if '-q' in sys.argv: |
|
192 from test import test_support |
|
193 test_support.verbose = 0 |
|
194 __import__('test.test_' + called_as.lower()) |