blob: 704ea59b32a3b5c5bd2d92465fa21760196be026 [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 +0000165class MutableString(UserString, collections.MutableSequence):
Fred Drakea22b5762000-04-03 03:51:50 +0000166 """mutable string objects
167
168 Python strings are immutable objects. This has the advantage, that
169 strings may be used as dictionary keys. If this property isn't needed
170 and you insist on changing string values in place instead, you may cheat
171 and use MutableString.
172
173 But the purpose of this class is an educational one: to prevent
174 people from inventing their own mutable string class derived
175 from UserString and than forget thereby to remove (override) the
Thomas Heller611dbc32003-08-27 10:48:12 +0000176 __hash__ method inherited from UserString. This would lead to
Fred Drakea22b5762000-04-03 03:51:50 +0000177 errors that would be very hard to track down.
178
179 A faster and better solution is to rewrite your program using lists."""
180 def __init__(self, string=""):
181 self.data = string
Tim Peterse1190062001-01-15 03:34:38 +0000182 def __hash__(self):
Collin Winterce36ad82007-08-30 01:19:48 +0000183 raise TypeError("unhashable type (it is mutable)")
Fred Drakea22b5762000-04-03 03:51:50 +0000184 def __setitem__(self, index, sub):
Thomas Woutersed03b412007-08-28 21:37:11 +0000185 if isinstance(index, slice):
186 if isinstance(sub, UserString):
187 sub = sub.data
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000188 elif not isinstance(sub, str):
Thomas Woutersed03b412007-08-28 21:37:11 +0000189 sub = str(sub)
190 start, stop, step = index.indices(len(self.data))
191 if step == -1:
192 start, stop = stop+1, start+1
193 sub = sub[::-1]
194 elif step != 1:
195 # XXX(twouters): I guess we should be reimplementing
196 # the extended slice assignment/deletion algorithm here...
Collin Winter4902e692007-08-30 18:18:27 +0000197 raise TypeError("invalid step in slicing assignment")
Thomas Woutersed03b412007-08-28 21:37:11 +0000198 start = min(start, stop)
199 self.data = self.data[:start] + sub + self.data[stop:]
200 else:
201 if index < 0:
202 index += len(self.data)
203 if index < 0 or index >= len(self.data): raise IndexError
204 self.data = self.data[:index] + sub + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000205 def __delitem__(self, index):
Thomas Woutersed03b412007-08-28 21:37:11 +0000206 if isinstance(index, slice):
207 start, stop, step = index.indices(len(self.data))
208 if step == -1:
209 start, stop = stop+1, start+1
210 elif step != 1:
211 # XXX(twouters): see same block in __setitem__
Collin Winter4902e692007-08-30 18:18:27 +0000212 raise TypeError("invalid step in slicing deletion")
Thomas Woutersed03b412007-08-28 21:37:11 +0000213 start = min(start, stop)
214 self.data = self.data[:start] + self.data[stop:]
215 else:
216 if index < 0:
217 index += len(self.data)
218 if index < 0 or index >= len(self.data): raise IndexError
219 self.data = self.data[:index] + self.data[index+1:]
Fred Drakea22b5762000-04-03 03:51:50 +0000220 def immutable(self):
221 return UserString(self.data)
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000222 def __iadd__(self, other):
223 if isinstance(other, UserString):
224 self.data += other.data
Guido van Rossum3172c5d2007-10-16 18:12:55 +0000225 elif isinstance(other, str):
Raymond Hettingerc35491e2002-08-09 01:37:06 +0000226 self.data += other
227 else:
228 self.data += str(other)
229 return self
230 def __imul__(self, n):
231 self.data *= n
232 return self
Raymond Hettinger6cc14a02008-02-06 22:14:55 +0000233 def insert(self, index, value):
234 self[index:index] = value
Tim Peterse1190062001-01-15 03:34:38 +0000235
Fred Drakea22b5762000-04-03 03:51:50 +0000236if __name__ == "__main__":
237 # execute the regression test to stdout, if called as a script:
238 import os
239 called_in_dir, called_as = os.path.split(sys.argv[0])
Fred Drakea22b5762000-04-03 03:51:50 +0000240 called_as, py = os.path.splitext(called_as)
Fred Drakea22b5762000-04-03 03:51:50 +0000241 if '-q' in sys.argv:
Barry Warsaw408b6d32002-07-30 23:27:12 +0000242 from test import test_support
Fred Drakea22b5762000-04-03 03:51:50 +0000243 test_support.verbose = 0
Barry Warsaw408b6d32002-07-30 23:27:12 +0000244 __import__('test.test_' + called_as.lower())