#!/usr/bin/env python## vim:ts=4:et:nowrap"""A user-defined wrapper around string objectsNote: string objects have grown methods in Python 1.6This module requires Python 1.6 or later."""fromtypesimportStringTypesimportsys__all__=["UserString","MutableString"]classUserString:def__init__(self,seq):ifisinstance(seq,StringTypes):self.data=seqelifisinstance(seq,UserString):self.data=seq.data[:]else:self.data=str(seq)def__str__(self):returnstr(self.data)def__repr__(self):returnrepr(self.data)def__int__(self):returnint(self.data)def__long__(self):returnlong(self.data)def__float__(self):returnfloat(self.data)def__complex__(self):returncomplex(self.data)def__hash__(self):returnhash(self.data)def__cmp__(self,string):ifisinstance(string,UserString):returncmp(self.data,string.data)else:returncmp(self.data,string)def__contains__(self,char):returncharinself.datadef__len__(self):returnlen(self.data)def__getitem__(self,index):returnself.__class__(self.data[index])def__getslice__(self,start,end):start=max(start,0);end=max(end,0)returnself.__class__(self.data[start:end])def__add__(self,other):ifisinstance(other,UserString):returnself.__class__(self.data+other.data)elifisinstance(other,StringTypes):returnself.__class__(self.data+other)else:returnself.__class__(self.data+str(other))def__radd__(self,other):ifisinstance(other,StringTypes):returnself.__class__(other+self.data)else:returnself.__class__(str(other)+self.data)def__mul__(self,n):returnself.__class__(self.data*n)__rmul__=__mul__def__mod__(self,args):returnself.__class__(self.data%args)# the following methods are defined in alphabetical order:defcapitalize(self):returnself.__class__(self.data.capitalize())defcenter(self,width,*args):returnself.__class__(self.data.center(width,*args))defcount(self,sub,start=0,end=sys.maxint):returnself.data.count(sub,start,end)defdecode(self,encoding=None,errors=None):# XXX improve this?ifencoding:iferrors:returnself.__class__(self.data.decode(encoding,errors))else:returnself.__class__(self.data.decode(encoding))else:returnself.__class__(self.data.decode())defencode(self,encoding=None,errors=None):# XXX improve this?ifencoding:iferrors:returnself.__class__(self.data.encode(encoding,errors))else:returnself.__class__(self.data.encode(encoding))else:returnself.__class__(self.data.encode())defendswith(self,suffix,start=0,end=sys.maxint):returnself.data.endswith(suffix,start,end)defexpandtabs(self,tabsize=8):returnself.__class__(self.data.expandtabs(tabsize))deffind(self,sub,start=0,end=sys.maxint):returnself.data.find(sub,start,end)defindex(self,sub,start=0,end=sys.maxint):returnself.data.index(sub,start,end)defisalpha(self):returnself.data.isalpha()defisalnum(self):returnself.data.isalnum()defisdecimal(self):returnself.data.isdecimal()defisdigit(self):returnself.data.isdigit()defislower(self):returnself.data.islower()defisnumeric(self):returnself.data.isnumeric()defisspace(self):returnself.data.isspace()defistitle(self):returnself.data.istitle()defisupper(self):returnself.data.isupper()defjoin(self,seq):returnself.data.join(seq)defljust(self,width,*args):returnself.__class__(self.data.ljust(width,*args))deflower(self):returnself.__class__(self.data.lower())deflstrip(self,chars=None):returnself.__class__(self.data.lstrip(chars))defreplace(self,old,new,maxsplit=-1):returnself.__class__(self.data.replace(old,new,maxsplit))defrfind(self,sub,start=0,end=sys.maxint):returnself.data.rfind(sub,start,end)defrindex(self,sub,start=0,end=sys.maxint):returnself.data.rindex(sub,start,end)defrjust(self,width,*args):returnself.__class__(self.data.rjust(width,*args))defrstrip(self,chars=None):returnself.__class__(self.data.rstrip(chars))defsplit(self,sep=None,maxsplit=-1):returnself.data.split(sep,maxsplit)defrsplit(self,sep=None,maxsplit=-1):returnself.data.rsplit(sep,maxsplit)defsplitlines(self,keepends=0):returnself.data.splitlines(keepends)defstartswith(self,prefix,start=0,end=sys.maxint):returnself.data.startswith(prefix,start,end)defstrip(self,chars=None):returnself.__class__(self.data.strip(chars))defswapcase(self):returnself.__class__(self.data.swapcase())deftitle(self):returnself.__class__(self.data.title())deftranslate(self,*args):returnself.__class__(self.data.translate(*args))defupper(self):returnself.__class__(self.data.upper())defzfill(self,width):returnself.__class__(self.data.zfill(width))classMutableString(UserString):"""mutable string objects Python strings are immutable objects. This has the advantage, that strings may be used as dictionary keys. If this property isn't needed and you insist on changing string values in place instead, you may cheat and use MutableString. But the purpose of this class is an educational one: to prevent people from inventing their own mutable string class derived from UserString and than forget thereby to remove (override) the __hash__ method inherited from UserString. This would lead to errors that would be very hard to track down. A faster and better solution is to rewrite your program using lists."""def__init__(self,string=""):self.data=stringdef__hash__(self):raiseTypeError,"unhashable type (it is mutable)"def__setitem__(self,index,sub):ifindex<0orindex>=len(self.data):raiseIndexErrorself.data=self.data[:index]+sub+self.data[index+1:]def__delitem__(self,index):ifindex<0orindex>=len(self.data):raiseIndexErrorself.data=self.data[:index]+self.data[index+1:]def__setslice__(self,start,end,sub):start=max(start,0);end=max(end,0)ifisinstance(sub,UserString):self.data=self.data[:start]+sub.data+self.data[end:]elifisinstance(sub,StringTypes):self.data=self.data[:start]+sub+self.data[end:]else:self.data=self.data[:start]+str(sub)+self.data[end:]def__delslice__(self,start,end):start=max(start,0);end=max(end,0)self.data=self.data[:start]+self.data[end:]defimmutable(self):returnUserString(self.data)def__iadd__(self,other):ifisinstance(other,UserString):self.data+=other.dataelifisinstance(other,StringTypes):self.data+=otherelse:self.data+=str(other)returnselfdef__imul__(self,n):self.data*=nreturnselfif__name__=="__main__":# execute the regression test to stdout, if called as a script:importoscalled_in_dir,called_as=os.path.split(sys.argv[0])called_as,py=os.path.splitext(called_as)if'-q'insys.argv:fromtestimporttest_supporttest_support.verbose=0__import__('test.test_'+called_as.lower())