Home | History | Annotate | Download | only in Lib
      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 import collections
     10 
     11 __all__ = ["UserString","MutableString"]
     12 
     13 class UserString(collections.Sequence):
     14     def __init__(self, seq):
     15         if isinstance(seq, basestring):
     16             self.data = seq
     17         elif isinstance(seq, UserString):
     18             self.data = seq.data[:]
     19         else:
     20             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)
     24     def __long__(self): return long(self.data)
     25     def __float__(self): return float(self.data)
     26     def __complex__(self): return complex(self.data)
     27     def __hash__(self): return hash(self.data)
     28 
     29     def __cmp__(self, string):
     30         if isinstance(string, UserString):
     31             return cmp(self.data, string.data)
     32         else:
     33             return cmp(self.data, string)
     34     def __contains__(self, char):
     35         return char in self.data
     36 
     37     def __len__(self): return len(self.data)
     38     def __getitem__(self, index): return self.__class__(self.data[index])
     39     def __getslice__(self, start, end):
     40         start = max(start, 0); end = max(end, 0)
     41         return self.__class__(self.data[start:end])
     42 
     43     def __add__(self, other):
     44         if isinstance(other, UserString):
     45             return self.__class__(self.data + other.data)
     46         elif isinstance(other, basestring):
     47             return self.__class__(self.data + other)
     48         else:
     49             return self.__class__(self.data + str(other))
     50     def __radd__(self, other):
     51         if isinstance(other, basestring):
     52             return self.__class__(other + self.data)
     53         else:
     54             return self.__class__(str(other) + self.data)
     55     def __mul__(self, n):
     56         return self.__class__(self.data*n)
     57     __rmul__ = __mul__
     58     def __mod__(self, args):
     59         return self.__class__(self.data % args)
     60 
     61     # the following methods are defined in alphabetical order:

     62     def capitalize(self): return self.__class__(self.data.capitalize())
     63     def center(self, width, *args):
     64         return self.__class__(self.data.center(width, *args))
     65     def count(self, sub, start=0, end=sys.maxint):
     66         return self.data.count(sub, start, end)
     67     def decode(self, encoding=None, errors=None): # XXX improve this?

     68         if encoding:
     69             if errors:
     70                 return self.__class__(self.data.decode(encoding, errors))
     71             else:
     72                 return self.__class__(self.data.decode(encoding))
     73         else:
     74             return self.__class__(self.data.decode())
     75     def encode(self, encoding=None, errors=None): # XXX improve this?

     76         if encoding:
     77             if errors:
     78                 return self.__class__(self.data.encode(encoding, errors))
     79             else:
     80                 return self.__class__(self.data.encode(encoding))
     81         else:
     82             return self.__class__(self.data.encode())
     83     def endswith(self, suffix, start=0, end=sys.maxint):
     84         return self.data.endswith(suffix, start, end)
     85     def expandtabs(self, tabsize=8):
     86         return self.__class__(self.data.expandtabs(tabsize))
     87     def find(self, sub, start=0, end=sys.maxint):
     88         return self.data.find(sub, start, end)
     89     def index(self, sub, start=0, end=sys.maxint):
     90         return self.data.index(sub, start, end)
     91     def isalpha(self): return self.data.isalpha()
     92     def isalnum(self): return self.data.isalnum()
     93     def isdecimal(self): return self.data.isdecimal()
     94     def isdigit(self): return self.data.isdigit()
     95     def islower(self): return self.data.islower()
     96     def isnumeric(self): return self.data.isnumeric()
     97     def isspace(self): return self.data.isspace()
     98     def istitle(self): return self.data.istitle()
     99     def isupper(self): return self.data.isupper()
    100     def join(self, seq): return self.data.join(seq)
    101     def ljust(self, width, *args):
    102         return self.__class__(self.data.ljust(width, *args))
    103     def lower(self): return self.__class__(self.data.lower())
    104     def lstrip(self, chars=None): return self.__class__(self.data.lstrip(chars))
    105     def partition(self, sep):
    106         return self.data.partition(sep)
    107     def replace(self, old, new, maxsplit=-1):
    108         return self.__class__(self.data.replace(old, new, maxsplit))
    109     def rfind(self, sub, start=0, end=sys.maxint):
    110         return self.data.rfind(sub, start, end)
    111     def rindex(self, sub, start=0, end=sys.maxint):
    112         return self.data.rindex(sub, start, end)
    113     def rjust(self, width, *args):
    114         return self.__class__(self.data.rjust(width, *args))
    115     def rpartition(self, sep):
    116         return self.data.rpartition(sep)
    117     def rstrip(self, chars=None): return self.__class__(self.data.rstrip(chars))
    118     def split(self, sep=None, maxsplit=-1):
    119         return self.data.split(sep, maxsplit)
    120     def rsplit(self, sep=None, maxsplit=-1):
    121         return self.data.rsplit(sep, maxsplit)
    122     def splitlines(self, keepends=0): return self.data.splitlines(keepends)
    123     def startswith(self, prefix, start=0, end=sys.maxint):
    124         return self.data.startswith(prefix, start, end)
    125     def strip(self, chars=None): return self.__class__(self.data.strip(chars))
    126     def swapcase(self): return self.__class__(self.data.swapcase())
    127     def title(self): return self.__class__(self.data.title())
    128     def translate(self, *args):
    129         return self.__class__(self.data.translate(*args))
    130     def upper(self): return self.__class__(self.data.upper())
    131     def zfill(self, width): return self.__class__(self.data.zfill(width))
    132 
    133 class MutableString(UserString, collections.MutableSequence):
    134     """mutable string objects
    135 
    136     Python strings are immutable objects.  This has the advantage, that
    137     strings may be used as dictionary keys.  If this property isn't needed
    138     and you insist on changing string values in place instead, you may cheat
    139     and use MutableString.
    140 
    141     But the purpose of this class is an educational one: to prevent
    142     people from inventing their own mutable string class derived
    143     from UserString and than forget thereby to remove (override) the
    144     __hash__ method inherited from UserString.  This would lead to
    145     errors that would be very hard to track down.
    146 
    147     A faster and better solution is to rewrite your program using lists."""
    148     def __init__(self, string=""):
    149         from warnings import warnpy3k
    150         warnpy3k('the class UserString.MutableString has been removed in '
    151                     'Python 3.0', stacklevel=2)
    152         self.data = string
    153 
    154     # We inherit object.__hash__, so we must deny this explicitly

    155     __hash__ = None
    156 
    157     def __setitem__(self, index, sub):
    158         if isinstance(index, slice):
    159             if isinstance(sub, UserString):
    160                 sub = sub.data
    161             elif not isinstance(sub, basestring):
    162                 sub = str(sub)
    163             start, stop, step = index.indices(len(self.data))
    164             if step == -1:
    165                 start, stop = stop+1, start+1
    166                 sub = sub[::-1]
    167             elif step != 1:
    168                 # XXX(twouters): I guess we should be reimplementing

    169                 # the extended slice assignment/deletion algorithm here...

    170                 raise TypeError, "invalid step in slicing assignment"
    171             start = min(start, stop)
    172             self.data = self.data[:start] + sub + self.data[stop:]
    173         else:
    174             if index < 0:
    175                 index += len(self.data)
    176             if index < 0 or index >= len(self.data): raise IndexError
    177             self.data = self.data[:index] + sub + self.data[index+1:]
    178     def __delitem__(self, index):
    179         if isinstance(index, slice):
    180             start, stop, step = index.indices(len(self.data))
    181             if step == -1:
    182                 start, stop = stop+1, start+1
    183             elif step != 1:
    184                 # XXX(twouters): see same block in __setitem__

    185                 raise TypeError, "invalid step in slicing deletion"
    186             start = min(start, stop)
    187             self.data = self.data[:start] + self.data[stop:]
    188         else:
    189             if index < 0:
    190                 index += len(self.data)
    191             if index < 0 or index >= len(self.data): raise IndexError
    192             self.data = self.data[:index] + self.data[index+1:]
    193     def __setslice__(self, start, end, sub):
    194         start = max(start, 0); end = max(end, 0)
    195         if isinstance(sub, UserString):
    196             self.data = self.data[:start]+sub.data+self.data[end:]
    197         elif isinstance(sub, basestring):
    198             self.data = self.data[:start]+sub+self.data[end:]
    199         else:
    200             self.data =  self.data[:start]+str(sub)+self.data[end:]
    201     def __delslice__(self, start, end):
    202         start = max(start, 0); end = max(end, 0)
    203         self.data = self.data[:start] + self.data[end:]
    204     def immutable(self):
    205         return UserString(self.data)
    206     def __iadd__(self, other):
    207         if isinstance(other, UserString):
    208             self.data += other.data
    209         elif isinstance(other, basestring):
    210             self.data += other
    211         else:
    212             self.data += str(other)
    213         return self
    214     def __imul__(self, n):
    215         self.data *= n
    216         return self
    217     def insert(self, index, value):
    218         self[index:index] = value
    219 
    220 if __name__ == "__main__":
    221     # execute the regression test to stdout, if called as a script:

    222     import os
    223     called_in_dir, called_as = os.path.split(sys.argv[0])
    224     called_as, py = os.path.splitext(called_as)
    225     if '-q' in sys.argv:
    226         from test import test_support
    227         test_support.verbose = 0
    228     __import__('test.test_' + called_as.lower())
    229