blob: de50396455c3e5372f179705ecc0af717a1db13e [file] [log] [blame]
Fred Drakea22b5762000-04-03 03:51:50 +00001#!/usr/bin/env python
2## vim:ts=4:et:nowrap
3"""A user-defined wrapper around string objects
4
Tim Peterse1190062001-01-15 03:34:38 +00005Note: string objects have grown methods in Python 1.6
Fred Drakea22b5762000-04-03 03:51:50 +00006This module requires Python 1.6 or later.
7"""
Fred Drakea22b5762000-04-03 03:51:50 +00008import sys
9
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000010__all__ = ["UserString","MutableString"]
11
Fred Drakea22b5762000-04-03 03:51:50 +000012class UserString:
13 def __init__(self, seq):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000014 if isinstance(seq, basestring):
Fred Drakea22b5762000-04-03 03:51:50 +000015 self.data = seq
16 elif isinstance(seq, UserString):
17 self.data = seq.data[:]
Tim Peterse1190062001-01-15 03:34:38 +000018 else:
Fred Drakea22b5762000-04-03 03:51:50 +000019 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)
Guido van Rossume2a383d2007-01-15 16:59:06 +000023 def __long__(self): return int(self.data)
Fred Drakea22b5762000-04-03 03:51:50 +000024 def __float__(self): return float(self.data)
25 def __complex__(self): return complex(self.data)
26 def __hash__(self): return hash(self.data)
27
Guido van Rossum47b9ff62006-08-24 00:41:19 +000028 def __eq__(self, string):
Fred Drakea22b5762000-04-03 03:51:50 +000029 if isinstance(string, UserString):
Guido van Rossum47b9ff62006-08-24 00:41:19 +000030 return self.data == string.data
Fred Drakea22b5762000-04-03 03:51:50 +000031 else:
Guido van Rossum47b9ff62006-08-24 00:41:19 +000032 return self.data == string
33 def __ne__(self, string):
34 if isinstance(string, UserString):
35 return self.data != string.data
36 else:
37 return self.data != string
38 def __lt__(self, string):
39 if isinstance(string, UserString):
40 return self.data < string.data
41 else:
42 return self.data < string
43 def __le__(self, string):
44 if isinstance(string, UserString):
45 return self.data <= string.data
46 else:
47 return self.data <= string
48 def __gt__(self, string):
49 if isinstance(string, UserString):
50 return self.data > string.data
51 else:
52 return self.data > string
53 def __ge__(self, string):
54 if isinstance(string, UserString):
55 return self.data >= string.data
56 else:
57 return self.data >= string
58
Fred Drakea22b5762000-04-03 03:51:50 +000059 def __contains__(self, char):
Guido van Rossum98b349f2007-08-27 21:47:52 +000060 if isinstance(char, UserString):
61 char = char.data
Fred Drakea22b5762000-04-03 03:51:50 +000062 return char in self.data
63
64 def __len__(self): return len(self.data)
65 def __getitem__(self, index): return self.__class__(self.data[index])
66 def __getslice__(self, start, end):
67 start = max(start, 0); end = max(end, 0)
68 return self.__class__(self.data[start:end])
69
70 def __add__(self, other):
71 if isinstance(other, UserString):
72 return self.__class__(self.data + other.data)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000073 elif isinstance(other, basestring):
Fred Drakea22b5762000-04-03 03:51:50 +000074 return self.__class__(self.data + other)
75 else:
76 return self.__class__(self.data + str(other))
77 def __radd__(self, other):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000078 if isinstance(other, basestring):
Fred Drakea22b5762000-04-03 03:51:50 +000079 return self.__class__(other + self.data)
80 else:
81 return self.__class__(str(other) + self.data)
82 def __mul__(self, n):
83 return self.__class__(self.data*n)
84 __rmul__ = __mul__
Neil Schemenauerfe4f7692002-11-18 16:12:54 +000085 def __mod__(self, args):
86 return self.__class__(self.data % args)
Fred Drakea22b5762000-04-03 03:51:50 +000087
88 # the following methods are defined in alphabetical order:
89 def capitalize(self): return self.__class__(self.data.capitalize())
Raymond Hettinger4f8f9762003-11-26 08:21:35 +000090 def center(self, width, *args):
91 return self.__class__(self.data.center(width, *args))
Fred Drakea22b5762000-04-03 03:51:50 +000092 def count(self, sub, start=0, end=sys.maxint):
Guido van Rossum98b349f2007-08-27 21:47:52 +000093 if isinstance(sub, UserString):
94 sub = sub.data
Fred Drakea22b5762000-04-03 03:51:50 +000095 return self.data.count(sub, start, end)
Marc-André Lemburg2d920412001-05-15 12:00:02 +000096 def decode(self, encoding=None, errors=None): # XXX improve this?
97 if encoding:
98 if errors:
99 return self.__class__(self.data.decode(encoding, errors))
100 else:
101 return self.__class__(self.data.decode(encoding))
102 else:
103 return self.__class__(self.data.decode())
Fred Drakea22b5762000-04-03 03:51:50 +0000104 def encode(self, encoding=None, errors=None): # XXX improve this?
105 if encoding:
106 if errors:
107 return self.__class__(self.data.encode(encoding, errors))
108 else:
109 return self.__class__(self.data.encode(encoding))
Tim Peterse1190062001-01-15 03:34:38 +0000110 else:
Fred Drakea22b5762000-04-03 03:51:50 +0000111 return self.__class__(self.data.encode())
112 def endswith(self, suffix, start=0, end=sys.maxint):
113 return self.data.endswith(suffix, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000114 def expandtabs(self, tabsize=8):
Fred Drakea22b5762000-04-03 03:51:50 +0000115 return self.__class__(self.data.expandtabs(tabsize))
Tim Peterse1190062001-01-15 03:34:38 +0000116 def find(self, sub, start=0, end=sys.maxint):
Guido van Rossum98b349f2007-08-27 21:47:52 +0000117 if isinstance(sub, UserString):
118 sub = sub.data
Fred Drakea22b5762000-04-03 03:51:50 +0000119 return self.data.find(sub, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000120 def index(self, sub, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000121 return self.data.index(sub, start, end)
Jeremy Hyltonfd547572000-07-10 17:07:17 +0000122 def isalpha(self): return self.data.isalpha()
123 def isalnum(self): return self.data.isalnum()
Fred Drakea22b5762000-04-03 03:51:50 +0000124 def isdecimal(self): return self.data.isdecimal()
125 def isdigit(self): return self.data.isdigit()
126 def islower(self): return self.data.islower()
127 def isnumeric(self): return self.data.isnumeric()
128 def isspace(self): return self.data.isspace()
129 def istitle(self): return self.data.istitle()
130 def isupper(self): return self.data.isupper()
131 def join(self, seq): return self.data.join(seq)
Raymond Hettinger4f8f9762003-11-26 08:21:35 +0000132 def ljust(self, width, *args):
133 return self.__class__(self.data.ljust(width, *args))
Fred Drakea22b5762000-04-03 03:51:50 +0000134 def lower(self): return self.__class__(self.data.lower())
Neal Norwitzffe33b72003-04-10 22:35:32 +0000135 def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000136 def partition(self, sep):
137 return self.data.partition(sep)
Tim Peterse1190062001-01-15 03:34:38 +0000138 def replace(self, old, new, maxsplit=-1):
Guido van Rossum98b349f2007-08-27 21:47:52 +0000139 if isinstance(old, UserString):
140 old = old.data
141 if isinstance(new, UserString):
142 new = new.data
Fred Drakea22b5762000-04-03 03:51:50 +0000143 return self.__class__(self.data.replace(old, new, maxsplit))
Tim Peterse1190062001-01-15 03:34:38 +0000144 def rfind(self, sub, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000145 return self.data.rfind(sub, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000146 def rindex(self, sub, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000147 return self.data.rindex(sub, start, end)
Raymond Hettinger4f8f9762003-11-26 08:21:35 +0000148 def rjust(self, width, *args):
149 return self.__class__(self.data.rjust(width, *args))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000150 def rpartition(self, sep):
151 return self.data.rpartition(sep)
Neal Norwitzffe33b72003-04-10 22:35:32 +0000152 def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars))
Tim Peterse1190062001-01-15 03:34:38 +0000153 def split(self, sep=None, maxsplit=-1):
Fred Drakea22b5762000-04-03 03:51:50 +0000154 return self.data.split(sep, maxsplit)
Hye-Shik Changeebb6412003-12-15 19:46:09 +0000155 def rsplit(self, sep=None, maxsplit=-1):
156 return self.data.rsplit(sep, maxsplit)
Guido van Rossum86662912000-04-11 15:38:46 +0000157 def splitlines(self, keepends=0): return self.data.splitlines(keepends)
Tim Peterse1190062001-01-15 03:34:38 +0000158 def startswith(self, prefix, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000159 return self.data.startswith(prefix, start, end)
Neal Norwitzffe33b72003-04-10 22:35:32 +0000160 def strip(self, chars=None): return self.__class__(self.data.strip(chars))
Fred Drakea22b5762000-04-03 03:51:50 +0000161 def swapcase(self): return self.__class__(self.data.swapcase())
162 def title(self): return self.__class__(self.data.title())
Tim Peterse1190062001-01-15 03:34:38 +0000163 def translate(self, *args):
Fred Drakea8939572000-08-21 21:47:20 +0000164 return self.__class__(self.data.translate(*args))
Fred Drakea22b5762000-04-03 03:51:50 +0000165 def upper(self): return self.__class__(self.data.upper())
Walter Dörwald068325e2002-04-15 13:36:47 +0000166 def zfill(self, width): return self.__class__(self.data.zfill(width))
Fred Drakea22b5762000-04-03 03:51:50 +0000167
168class MutableString(UserString):
169 """mutable string objects
170
171 Python strings are immutable objects. This has the advantage, that
172 strings may be used as dictionary keys. If this property isn't needed
173 and you insist on changing string values in place instead, you may cheat
174 and use MutableString.
175
176 But the purpose of this class is an educational one: to prevent
177 people from inventing their own mutable string class derived
178 from UserString and than forget thereby to remove (override) the
Thomas Heller611dbc32003-08-27 10:48:12 +0000179 __hash__ method inherited from UserString. This would lead to
Fred Drakea22b5762000-04-03 03:51:50 +0000180 errors that would be very hard to track down.
181
182 A faster and better solution is to rewrite your program using lists."""
183 def __init__(self, string=""):
184 self.data = string
Tim Peterse1190062001-01-15 03:34:38 +0000185 def __hash__(self):
Collin Winterce36ad82007-08-30 01:19:48 +0000186 raise TypeError("unhashable type (it is mutable)")
Fred Drakea22b5762000-04-03 03:51:50 +0000187 def __setitem__(self, index, sub):
Thomas Woutersed03b412007-08-28 21:37:11 +0000188 if isinstance(index, slice):
189 if isinstance(sub, UserString):
190 sub = sub.data
191 elif not isinstance(sub, basestring):
192 sub = str(sub)
193 start, stop, step = index.indices(len(self.data))
194 if step == -1:
195 start, stop = stop+1, start+1
196 sub = sub[::-1]
197 elif step != 1:
198 # XXX(twouters): I guess we should be reimplementing
199 # the extended slice assignment/deletion algorithm here...
Collin Winter4902e692007-08-30 18:18:27 +0000200 raise TypeError("invalid step in slicing assignment")
Thomas Woutersed03b412007-08-28 21:37:11 +0000201 start = min(start, stop)
202 self.data = self.data[:start] + sub + self.data[stop:]
203 else:
204 if index < 0:
205 index += len(self.data)
206 if index < 0 or index >= len(self.data): raise IndexError
207 self.data = self.data[:index] + sub + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000208 def __delitem__(self, index):
Thomas Woutersed03b412007-08-28 21:37:11 +0000209 if isinstance(index, slice):
210 start, stop, step = index.indices(len(self.data))
211 if step == -1:
212 start, stop = stop+1, start+1
213 elif step != 1:
214 # XXX(twouters): see same block in __setitem__
Collin Winter4902e692007-08-30 18:18:27 +0000215 raise TypeError("invalid step in slicing deletion")
Thomas Woutersed03b412007-08-28 21:37:11 +0000216 start = min(start, stop)
217 self.data = self.data[:start] + self.data[stop:]
218 else:
219 if index < 0:
220 index += len(self.data)
221 if index < 0 or index >= len(self.data): raise IndexError
222 self.data = self.data[:index] + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000223 def __setslice__(self, start, end, sub):
224 start = max(start, 0); end = max(end, 0)
225 if isinstance(sub, UserString):
226 self.data = self.data[:start]+sub.data+self.data[end:]
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000227 elif isinstance(sub, basestring):
Fred Drakea22b5762000-04-03 03:51:50 +0000228 self.data = self.data[:start]+sub+self.data[end:]
229 else:
230 self.data = self.data[:start]+str(sub)+self.data[end:]
231 def __delslice__(self, start, end):
232 start = max(start, 0); end = max(end, 0)
233 self.data = self.data[:start] + self.data[end:]
234 def immutable(self):
235 return UserString(self.data)
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000236 def __iadd__(self, other):
237 if isinstance(other, UserString):
238 self.data += other.data
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000239 elif isinstance(other, basestring):
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000240 self.data += other
241 else:
242 self.data += str(other)
243 return self
244 def __imul__(self, n):
245 self.data *= n
246 return self
Tim Peterse1190062001-01-15 03:34:38 +0000247
Fred Drakea22b5762000-04-03 03:51:50 +0000248if __name__ == "__main__":
249 # execute the regression test to stdout, if called as a script:
250 import os
251 called_in_dir, called_as = os.path.split(sys.argv[0])
Fred Drakea22b5762000-04-03 03:51:50 +0000252 called_as, py = os.path.splitext(called_as)
Fred Drakea22b5762000-04-03 03:51:50 +0000253 if '-q' in sys.argv:
Barry Warsaw408b6d32002-07-30 23:27:12 +0000254 from test import test_support
Fred Drakea22b5762000-04-03 03:51:50 +0000255 test_support.verbose = 0
Barry Warsaw408b6d32002-07-30 23:27:12 +0000256 __import__('test.test_' + called_as.lower())