blob: 615c135f164576706b329b8df68de98326184ca1 [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
Raymond Hettingerb8b6d3e2008-02-06 20:59:41 +00009import collections
Fred Drakea22b5762000-04-03 03:51:50 +000010
Skip Montanaroe99d5ea2001-01-20 19:54:20 +000011__all__ = ["UserString","MutableString"]
12
Raymond Hettingerb8b6d3e2008-02-06 20:59:41 +000013class UserString(collections.Sequence):
Fred Drakea22b5762000-04-03 03:51:50 +000014 def __init__(self, seq):
Guido van Rossum3172c5d2007-10-16 18:12:55 +000015 if isinstance(seq, str):
Fred Drakea22b5762000-04-03 03:51:50 +000016 self.data = seq
17 elif isinstance(seq, UserString):
18 self.data = seq.data[:]
Tim Peterse1190062001-01-15 03:34:38 +000019 else:
Fred Drakea22b5762000-04-03 03:51:50 +000020 self.data = str(seq)
21 def __str__(self): return str(self.data)
22 def __repr__(self): return repr(self.data)
23 def __int__(self): return int(self.data)
Guido van Rossume2a383d2007-01-15 16:59:06 +000024 def __long__(self): return int(self.data)
Fred Drakea22b5762000-04-03 03:51:50 +000025 def __float__(self): return float(self.data)
26 def __complex__(self): return complex(self.data)
27 def __hash__(self): return hash(self.data)
28
Guido van Rossum47b9ff62006-08-24 00:41:19 +000029 def __eq__(self, string):
Fred Drakea22b5762000-04-03 03:51:50 +000030 if isinstance(string, UserString):
Guido van Rossum47b9ff62006-08-24 00:41:19 +000031 return self.data == string.data
Fred Drakea22b5762000-04-03 03:51:50 +000032 else:
Guido van Rossum47b9ff62006-08-24 00:41:19 +000033 return self.data == string
34 def __ne__(self, string):
35 if isinstance(string, UserString):
36 return self.data != string.data
37 else:
38 return self.data != string
39 def __lt__(self, string):
40 if isinstance(string, UserString):
41 return self.data < string.data
42 else:
43 return self.data < string
44 def __le__(self, string):
45 if isinstance(string, UserString):
46 return self.data <= string.data
47 else:
48 return self.data <= string
49 def __gt__(self, string):
50 if isinstance(string, UserString):
51 return self.data > string.data
52 else:
53 return self.data > string
54 def __ge__(self, string):
55 if isinstance(string, UserString):
56 return self.data >= string.data
57 else:
58 return self.data >= string
59
Fred Drakea22b5762000-04-03 03:51:50 +000060 def __contains__(self, char):
Guido van Rossum98b349f2007-08-27 21:47:52 +000061 if isinstance(char, UserString):
62 char = char.data
Fred Drakea22b5762000-04-03 03:51:50 +000063 return char in self.data
64
65 def __len__(self): return len(self.data)
66 def __getitem__(self, index): return self.__class__(self.data[index])
Fred Drakea22b5762000-04-03 03:51:50 +000067 def __add__(self, other):
68 if isinstance(other, UserString):
69 return self.__class__(self.data + other.data)
Guido van Rossum3172c5d2007-10-16 18:12:55 +000070 elif isinstance(other, str):
Fred Drakea22b5762000-04-03 03:51:50 +000071 return self.__class__(self.data + other)
72 else:
73 return self.__class__(self.data + str(other))
74 def __radd__(self, other):
Guido van Rossum3172c5d2007-10-16 18:12:55 +000075 if isinstance(other, str):
Fred Drakea22b5762000-04-03 03:51:50 +000076 return self.__class__(other + self.data)
77 else:
78 return self.__class__(str(other) + self.data)
79 def __mul__(self, n):
80 return self.__class__(self.data*n)
81 __rmul__ = __mul__
Neil Schemenauerfe4f7692002-11-18 16:12:54 +000082 def __mod__(self, args):
83 return self.__class__(self.data % args)
Fred Drakea22b5762000-04-03 03:51:50 +000084
85 # the following methods are defined in alphabetical order:
86 def capitalize(self): return self.__class__(self.data.capitalize())
Raymond Hettinger4f8f9762003-11-26 08:21:35 +000087 def center(self, width, *args):
88 return self.__class__(self.data.center(width, *args))
Christian Heimesa37d4c62007-12-04 23:02:19 +000089 def count(self, sub, start=0, end=sys.maxsize):
Guido van Rossum98b349f2007-08-27 21:47:52 +000090 if isinstance(sub, UserString):
91 sub = sub.data
Fred Drakea22b5762000-04-03 03:51:50 +000092 return self.data.count(sub, start, end)
Marc-André Lemburg2d920412001-05-15 12:00:02 +000093 def decode(self, encoding=None, errors=None): # XXX improve this?
94 if encoding:
95 if errors:
96 return self.__class__(self.data.decode(encoding, errors))
97 else:
98 return self.__class__(self.data.decode(encoding))
99 else:
100 return self.__class__(self.data.decode())
Fred Drakea22b5762000-04-03 03:51:50 +0000101 def encode(self, encoding=None, errors=None): # XXX improve this?
102 if encoding:
103 if errors:
104 return self.__class__(self.data.encode(encoding, errors))
105 else:
106 return self.__class__(self.data.encode(encoding))
Tim Peterse1190062001-01-15 03:34:38 +0000107 else:
Fred Drakea22b5762000-04-03 03:51:50 +0000108 return self.__class__(self.data.encode())
Christian Heimesa37d4c62007-12-04 23:02:19 +0000109 def endswith(self, suffix, start=0, end=sys.maxsize):
Fred Drakea22b5762000-04-03 03:51:50 +0000110 return self.data.endswith(suffix, start, end)
Tim Peterse1190062001-01-15 03:34:38 +0000111 def expandtabs(self, tabsize=8):
Fred Drakea22b5762000-04-03 03:51:50 +0000112 return self.__class__(self.data.expandtabs(tabsize))
Christian Heimesa37d4c62007-12-04 23:02:19 +0000113 def find(self, sub, start=0, end=sys.maxsize):
Guido van Rossum98b349f2007-08-27 21:47:52 +0000114 if isinstance(sub, UserString):
115 sub = sub.data
Fred Drakea22b5762000-04-03 03:51:50 +0000116 return self.data.find(sub, start, end)
Christian Heimesa37d4c62007-12-04 23:02:19 +0000117 def index(self, sub, start=0, end=sys.maxsize):
Fred Drakea22b5762000-04-03 03:51:50 +0000118 return self.data.index(sub, start, end)
Jeremy Hyltonfd547572000-07-10 17:07:17 +0000119 def isalpha(self): return self.data.isalpha()
120 def isalnum(self): return self.data.isalnum()
Fred Drakea22b5762000-04-03 03:51:50 +0000121 def isdecimal(self): return self.data.isdecimal()
122 def isdigit(self): return self.data.isdigit()
123 def islower(self): return self.data.islower()
124 def isnumeric(self): return self.data.isnumeric()
125 def isspace(self): return self.data.isspace()
126 def istitle(self): return self.data.istitle()
127 def isupper(self): return self.data.isupper()
128 def join(self, seq): return self.data.join(seq)
Raymond Hettinger4f8f9762003-11-26 08:21:35 +0000129 def ljust(self, width, *args):
130 return self.__class__(self.data.ljust(width, *args))
Fred Drakea22b5762000-04-03 03:51:50 +0000131 def lower(self): return self.__class__(self.data.lower())
Neal Norwitzffe33b72003-04-10 22:35:32 +0000132 def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000133 def partition(self, sep):
134 return self.data.partition(sep)
Tim Peterse1190062001-01-15 03:34:38 +0000135 def replace(self, old, new, maxsplit=-1):
Guido van Rossum98b349f2007-08-27 21:47:52 +0000136 if isinstance(old, UserString):
137 old = old.data
138 if isinstance(new, UserString):
139 new = new.data
Fred Drakea22b5762000-04-03 03:51:50 +0000140 return self.__class__(self.data.replace(old, new, maxsplit))
Christian Heimesa37d4c62007-12-04 23:02:19 +0000141 def rfind(self, sub, start=0, end=sys.maxsize):
Fred Drakea22b5762000-04-03 03:51:50 +0000142 return self.data.rfind(sub, start, end)
Christian Heimesa37d4c62007-12-04 23:02:19 +0000143 def rindex(self, sub, start=0, end=sys.maxsize):
Fred Drakea22b5762000-04-03 03:51:50 +0000144 return self.data.rindex(sub, start, end)
Raymond Hettinger4f8f9762003-11-26 08:21:35 +0000145 def rjust(self, width, *args):
146 return self.__class__(self.data.rjust(width, *args))
Thomas Wouters477c8d52006-05-27 19:21:47 +0000147 def rpartition(self, sep):
148 return self.data.rpartition(sep)
Neal Norwitzffe33b72003-04-10 22:35:32 +0000149 def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars))
Tim Peterse1190062001-01-15 03:34:38 +0000150 def split(self, sep=None, maxsplit=-1):
Fred Drakea22b5762000-04-03 03:51:50 +0000151 return self.data.split(sep, maxsplit)
Hye-Shik Changeebb6412003-12-15 19:46:09 +0000152 def rsplit(self, sep=None, maxsplit=-1):
153 return self.data.rsplit(sep, maxsplit)
Guido van Rossum86662912000-04-11 15:38:46 +0000154 def splitlines(self, keepends=0): return self.data.splitlines(keepends)
Christian Heimesa37d4c62007-12-04 23:02:19 +0000155 def startswith(self, prefix, start=0, end=sys.maxsize):
Fred Drakea22b5762000-04-03 03:51:50 +0000156 return self.data.startswith(prefix, start, end)
Neal Norwitzffe33b72003-04-10 22:35:32 +0000157 def strip(self, chars=None): return self.__class__(self.data.strip(chars))
Fred Drakea22b5762000-04-03 03:51:50 +0000158 def swapcase(self): return self.__class__(self.data.swapcase())
159 def title(self): return self.__class__(self.data.title())
Tim Peterse1190062001-01-15 03:34:38 +0000160 def translate(self, *args):
Fred Drakea8939572000-08-21 21:47:20 +0000161 return self.__class__(self.data.translate(*args))
Fred Drakea22b5762000-04-03 03:51:50 +0000162 def upper(self): return self.__class__(self.data.upper())
Walter Dörwald068325e2002-04-15 13:36:47 +0000163 def zfill(self, width): return self.__class__(self.data.zfill(width))
Fred Drakea22b5762000-04-03 03:51:50 +0000164
Raymond Hettingerb8b6d3e2008-02-06 20:59:41 +0000165collections.Sequence.register(UserString)
166
167class MutableString(UserString, collections.MutableSequence):
Fred Drakea22b5762000-04-03 03:51:50 +0000168 """mutable string objects
169
170 Python strings are immutable objects. This has the advantage, that
171 strings may be used as dictionary keys. If this property isn't needed
172 and you insist on changing string values in place instead, you may cheat
173 and use MutableString.
174
175 But the purpose of this class is an educational one: to prevent
176 people from inventing their own mutable string class derived
177 from UserString and than forget thereby to remove (override) the
Thomas Heller611dbc32003-08-27 10:48:12 +0000178 __hash__ method inherited from UserString. This would lead to
Fred Drakea22b5762000-04-03 03:51:50 +0000179 errors that would be very hard to track down.
180
181 A faster and better solution is to rewrite your program using lists."""
182 def __init__(self, string=""):
183 self.data = string
Tim Peterse1190062001-01-15 03:34:38 +0000184 def __hash__(self):
Collin Winterce36ad82007-08-30 01:19:48 +0000185 raise TypeError("unhashable type (it is mutable)")
Fred Drakea22b5762000-04-03 03:51:50 +0000186 def __setitem__(self, index, sub):
Thomas Woutersed03b412007-08-28 21:37:11 +0000187 if isinstance(index, slice):
188 if isinstance(sub, UserString):
189 sub = sub.data
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000190 elif not isinstance(sub, str):
Thomas Woutersed03b412007-08-28 21:37:11 +0000191 sub = str(sub)
192 start, stop, step = index.indices(len(self.data))
193 if step == -1:
194 start, stop = stop+1, start+1
195 sub = sub[::-1]
196 elif step != 1:
197 # XXX(twouters): I guess we should be reimplementing
198 # the extended slice assignment/deletion algorithm here...
Collin Winter4902e692007-08-30 18:18:27 +0000199 raise TypeError("invalid step in slicing assignment")
Thomas Woutersed03b412007-08-28 21:37:11 +0000200 start = min(start, stop)
201 self.data = self.data[:start] + sub + self.data[stop:]
202 else:
203 if index < 0:
204 index += len(self.data)
205 if index < 0 or index >= len(self.data): raise IndexError
206 self.data = self.data[:index] + sub + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000207 def __delitem__(self, index):
Thomas Woutersed03b412007-08-28 21:37:11 +0000208 if isinstance(index, slice):
209 start, stop, step = index.indices(len(self.data))
210 if step == -1:
211 start, stop = stop+1, start+1
212 elif step != 1:
213 # XXX(twouters): see same block in __setitem__
Collin Winter4902e692007-08-30 18:18:27 +0000214 raise TypeError("invalid step in slicing deletion")
Thomas Woutersed03b412007-08-28 21:37:11 +0000215 start = min(start, stop)
216 self.data = self.data[:start] + self.data[stop:]
217 else:
218 if index < 0:
219 index += len(self.data)
220 if index < 0 or index >= len(self.data): raise IndexError
221 self.data = self.data[:index] + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000222 def immutable(self):
223 return UserString(self.data)
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000224 def __iadd__(self, other):
225 if isinstance(other, UserString):
226 self.data += other.data
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000227 elif isinstance(other, str):
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000228 self.data += other
229 else:
230 self.data += str(other)
231 return self
232 def __imul__(self, n):
233 self.data *= n
234 return self
Tim Peterse1190062001-01-15 03:34:38 +0000235
Raymond Hettingerb8b6d3e2008-02-06 20:59:41 +0000236collections.MutableSequence.register(MutableString)
237
Fred Drakea22b5762000-04-03 03:51:50 +0000238if __name__ == "__main__":
239 # execute the regression test to stdout, if called as a script:
240 import os
241 called_in_dir, called_as = os.path.split(sys.argv[0])
Fred Drakea22b5762000-04-03 03:51:50 +0000242 called_as, py = os.path.splitext(called_as)
Fred Drakea22b5762000-04-03 03:51:50 +0000243 if '-q' in sys.argv:
Barry Warsaw408b6d32002-07-30 23:27:12 +0000244 from test import test_support
Fred Drakea22b5762000-04-03 03:51:50 +0000245 test_support.verbose = 0
Barry Warsaw408b6d32002-07-30 23:27:12 +0000246 __import__('test.test_' + called_as.lower())