blob: 8417be76e4845e2ee318bd3326b94e515e0b6cd0 [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])
Fred Drakea22b5762000-04-03 03:51:50 +000066 def __add__(self, other):
67 if isinstance(other, UserString):
68 return self.__class__(self.data + other.data)
Thomas Wouters0e3f5912006-08-11 14:57:12 +000069 elif isinstance(other, basestring):
Fred Drakea22b5762000-04-03 03:51:50 +000070 return self.__class__(self.data + other)
71 else:
72 return self.__class__(self.data + str(other))
73 def __radd__(self, other):
Thomas Wouters0e3f5912006-08-11 14:57:12 +000074 if isinstance(other, basestring):
Fred Drakea22b5762000-04-03 03:51:50 +000075 return self.__class__(other + self.data)
76 else:
77 return self.__class__(str(other) + self.data)
78 def __mul__(self, n):
79 return self.__class__(self.data*n)
80 __rmul__ = __mul__
Neil Schemenauerfe4f7692002-11-18 16:12:54 +000081 def __mod__(self, args):
82 return self.__class__(self.data % args)
Fred Drakea22b5762000-04-03 03:51:50 +000083
84 # the following methods are defined in alphabetical order:
85 def capitalize(self): return self.__class__(self.data.capitalize())
Raymond Hettinger4f8f9762003-11-26 08:21:35 +000086 def center(self, width, *args):
87 return self.__class__(self.data.center(width, *args))
Fred Drakea22b5762000-04-03 03:51:50 +000088 def count(self, sub, start=0, end=sys.maxint):
Guido van Rossum98b349f2007-08-27 21:47:52 +000089 if isinstance(sub, UserString):
90 sub = sub.data
Fred Drakea22b5762000-04-03 03:51:50 +000091 return self.data.count(sub, start, end)
Marc-André Lemburg2d920412001-05-15 12:00:02 +000092 def decode(self, encoding=None, errors=None): # XXX improve this?
93 if encoding:
94 if errors:
95 return self.__class__(self.data.decode(encoding, errors))
96 else:
97 return self.__class__(self.data.decode(encoding))
98 else:
99 return self.__class__(self.data.decode())
Fred Drakea22b5762000-04-03 03:51:50 +0000100 def encode(self, encoding=None, errors=None): # XXX improve this?
101 if encoding:
102 if errors:
103 return self.__class__(self.data.encode(encoding, errors))
104 else:
105 return self.__class__(self.data.encode(encoding))
Tim Peterse1190062001-01-15 03:34:38 +0000106 else:
Fred Drakea22b5762000-04-03 03:51:50 +0000107 return self.__class__(self.data.encode())
108 def endswith(self, suffix, start=0, end=sys.maxint):
109 return self.data.endswith(suffix, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000110 def expandtabs(self, tabsize=8):
Fred Drakea22b5762000-04-03 03:51:50 +0000111 return self.__class__(self.data.expandtabs(tabsize))
Tim Peterse1190062001-01-15 03:34:38 +0000112 def find(self, sub, start=0, end=sys.maxint):
Guido van Rossum98b349f2007-08-27 21:47:52 +0000113 if isinstance(sub, UserString):
114 sub = sub.data
Fred Drakea22b5762000-04-03 03:51:50 +0000115 return self.data.find(sub, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000116 def index(self, sub, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000117 return self.data.index(sub, start, end)
Jeremy Hyltonfd547572000-07-10 17:07:17 +0000118 def isalpha(self): return self.data.isalpha()
119 def isalnum(self): return self.data.isalnum()
Fred Drakea22b5762000-04-03 03:51:50 +0000120 def isdecimal(self): return self.data.isdecimal()
121 def isdigit(self): return self.data.isdigit()
122 def islower(self): return self.data.islower()
123 def isnumeric(self): return self.data.isnumeric()
124 def isspace(self): return self.data.isspace()
125 def istitle(self): return self.data.istitle()
126 def isupper(self): return self.data.isupper()
127 def join(self, seq): return self.data.join(seq)
Raymond Hettinger4f8f9762003-11-26 08:21:35 +0000128 def ljust(self, width, *args):
129 return self.__class__(self.data.ljust(width, *args))
Fred Drakea22b5762000-04-03 03:51:50 +0000130 def lower(self): return self.__class__(self.data.lower())
Neal Norwitzffe33b72003-04-10 22:35:32 +0000131 def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000132 def partition(self, sep):
133 return self.data.partition(sep)
Tim Peterse1190062001-01-15 03:34:38 +0000134 def replace(self, old, new, maxsplit=-1):
Guido van Rossum98b349f2007-08-27 21:47:52 +0000135 if isinstance(old, UserString):
136 old = old.data
137 if isinstance(new, UserString):
138 new = new.data
Fred Drakea22b5762000-04-03 03:51:50 +0000139 return self.__class__(self.data.replace(old, new, maxsplit))
Tim Peterse1190062001-01-15 03:34:38 +0000140 def rfind(self, sub, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000141 return self.data.rfind(sub, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000142 def rindex(self, sub, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000143 return self.data.rindex(sub, start, end)
Raymond Hettinger4f8f9762003-11-26 08:21:35 +0000144 def rjust(self, width, *args):
145 return self.__class__(self.data.rjust(width, *args))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000146 def rpartition(self, sep):
147 return self.data.rpartition(sep)
Neal Norwitzffe33b72003-04-10 22:35:32 +0000148 def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars))
Tim Peterse1190062001-01-15 03:34:38 +0000149 def split(self, sep=None, maxsplit=-1):
Fred Drakea22b5762000-04-03 03:51:50 +0000150 return self.data.split(sep, maxsplit)
Hye-Shik Changeebb6412003-12-15 19:46:09 +0000151 def rsplit(self, sep=None, maxsplit=-1):
152 return self.data.rsplit(sep, maxsplit)
Guido van Rossum86662912000-04-11 15:38:46 +0000153 def splitlines(self, keepends=0): return self.data.splitlines(keepends)
Tim Peterse1190062001-01-15 03:34:38 +0000154 def startswith(self, prefix, start=0, end=sys.maxint):
Fred Drakea22b5762000-04-03 03:51:50 +0000155 return self.data.startswith(prefix, start, end)
Neal Norwitzffe33b72003-04-10 22:35:32 +0000156 def strip(self, chars=None): return self.__class__(self.data.strip(chars))
Fred Drakea22b5762000-04-03 03:51:50 +0000157 def swapcase(self): return self.__class__(self.data.swapcase())
158 def title(self): return self.__class__(self.data.title())
Tim Peterse1190062001-01-15 03:34:38 +0000159 def translate(self, *args):
Fred Drakea8939572000-08-21 21:47:20 +0000160 return self.__class__(self.data.translate(*args))
Fred Drakea22b5762000-04-03 03:51:50 +0000161 def upper(self): return self.__class__(self.data.upper())
Walter Dörwald068325e2002-04-15 13:36:47 +0000162 def zfill(self, width): return self.__class__(self.data.zfill(width))
Fred Drakea22b5762000-04-03 03:51:50 +0000163
164class MutableString(UserString):
165 """mutable string objects
166
167 Python strings are immutable objects. This has the advantage, that
168 strings may be used as dictionary keys. If this property isn't needed
169 and you insist on changing string values in place instead, you may cheat
170 and use MutableString.
171
172 But the purpose of this class is an educational one: to prevent
173 people from inventing their own mutable string class derived
174 from UserString and than forget thereby to remove (override) the
Thomas Heller611dbc32003-08-27 10:48:12 +0000175 __hash__ method inherited from UserString. This would lead to
Fred Drakea22b5762000-04-03 03:51:50 +0000176 errors that would be very hard to track down.
177
178 A faster and better solution is to rewrite your program using lists."""
179 def __init__(self, string=""):
180 self.data = string
Tim Peterse1190062001-01-15 03:34:38 +0000181 def __hash__(self):
Collin Winterce36ad82007-08-30 01:19:48 +0000182 raise TypeError("unhashable type (it is mutable)")
Fred Drakea22b5762000-04-03 03:51:50 +0000183 def __setitem__(self, index, sub):
Thomas Woutersed03b412007-08-28 21:37:11 +0000184 if isinstance(index, slice):
185 if isinstance(sub, UserString):
186 sub = sub.data
187 elif not isinstance(sub, basestring):
188 sub = str(sub)
189 start, stop, step = index.indices(len(self.data))
190 if step == -1:
191 start, stop = stop+1, start+1
192 sub = sub[::-1]
193 elif step != 1:
194 # XXX(twouters): I guess we should be reimplementing
195 # the extended slice assignment/deletion algorithm here...
Collin Winter4902e692007-08-30 18:18:27 +0000196 raise TypeError("invalid step in slicing assignment")
Thomas Woutersed03b412007-08-28 21:37:11 +0000197 start = min(start, stop)
198 self.data = self.data[:start] + sub + self.data[stop:]
199 else:
200 if index < 0:
201 index += len(self.data)
202 if index < 0 or index >= len(self.data): raise IndexError
203 self.data = self.data[:index] + sub + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000204 def __delitem__(self, index):
Thomas Woutersed03b412007-08-28 21:37:11 +0000205 if isinstance(index, slice):
206 start, stop, step = index.indices(len(self.data))
207 if step == -1:
208 start, stop = stop+1, start+1
209 elif step != 1:
210 # XXX(twouters): see same block in __setitem__
Collin Winter4902e692007-08-30 18:18:27 +0000211 raise TypeError("invalid step in slicing deletion")
Thomas Woutersed03b412007-08-28 21:37:11 +0000212 start = min(start, stop)
213 self.data = self.data[:start] + self.data[stop:]
214 else:
215 if index < 0:
216 index += len(self.data)
217 if index < 0 or index >= len(self.data): raise IndexError
218 self.data = self.data[:index] + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000219 def immutable(self):
220 return UserString(self.data)
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000221 def __iadd__(self, other):
222 if isinstance(other, UserString):
223 self.data += other.data
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000224 elif isinstance(other, basestring):
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000225 self.data += other
226 else:
227 self.data += str(other)
228 return self
229 def __imul__(self, n):
230 self.data *= n
231 return self
Tim Peterse1190062001-01-15 03:34:38 +0000232
Fred Drakea22b5762000-04-03 03:51:50 +0000233if __name__ == "__main__":
234 # execute the regression test to stdout, if called as a script:
235 import os
236 called_in_dir, called_as = os.path.split(sys.argv[0])
Fred Drakea22b5762000-04-03 03:51:50 +0000237 called_as, py = os.path.splitext(called_as)
Fred Drakea22b5762000-04-03 03:51:50 +0000238 if '-q' in sys.argv:
Barry Warsaw408b6d32002-07-30 23:27:12 +0000239 from test import test_support
Fred Drakea22b5762000-04-03 03:51:50 +0000240 test_support.verbose = 0
Barry Warsaw408b6d32002-07-30 23:27:12 +0000241 __import__('test.test_' + called_as.lower())