# $Id: chararray.py,v 1.10 2002/03/11 22:28:55 jaytmiller Exp $ # from copy import _EmptyClass import memory import _chararray import numarray import sys import string import types import os import re _globals, _locals = globals, locals class CharArrayType: def __init__(self, itemsize): self.itemsize = itemsize self.name = "CharArrayType[%d]" % (self.itemsize,) def __repr__(self): return self.name CharArrayTypeCache = {} def NewCharArrayType(itemsize): """NewCharArrayType creates CharArrayTypes on demand, but checks to see if they already exist in the cache first. This makes type equivalence the same as object identity. """ if itemsize not in CharArrayTypeCache.keys(): CharArrayTypeCache[itemsize] = CharArrayType(itemsize) return CharArrayTypeCache[itemsize] class RawCharArray(numarray.NDArray): """RawCharArray(buffer=None, shape=None, byteoffset=0, bytestride=None) RawCharArray is a fixed length array of characters based on ndarray.NDArray with no automatic stripping or padding. itemsize specifies the length of all strings in the array. """ def __init__(self, buffer=None, itemsize=None, shape=None, byteoffset=0, bytestride=None, aligned=1, type=None): if isinstance(shape, types.IntType): shape = (shape,) if type is not None: if itemsize is not None: raise ValueError("Specify type *or* itemsize, not both.") itemsize = type.itemsize if buffer is None: if shape is None or itemsize is None: raise ValueError("Must define both shape & itemsize if buffer is None") else: if shape is None and itemsize is None: raise ValueError("Must specify shape, itemsize, or both.") ni = _bufferItems( buffer, byteoffset, bytestride, itemsize) if shape and itemsize == None: itemsize = ni/numarray.product(shape) if itemsize and shape == None: shape = (ni,) if itemsize == 0: # Another hack for 0 length strings. bytestride=0 elif numarray.product(shape) > ni: raise ValueError("Inconsistent string and array parameters.") numarray.NDArray.__init__(self, shape=shape, itemsize=itemsize, buffer=buffer, byteoffset=byteoffset, bytestride=bytestride, aligned=aligned) if type is None: type = NewCharArrayType(itemsize) self._type = type self._byteswap = 0 if buffer is None: self.fill(" ") def _getitem(self, key): """_getitem(self, byteoffset) returns the "stripped" fixed length string from 'self' at 'byteoffset'. """ byteoffset = self._getByteOffset(key) return self.strip(str( self._data[byteoffset:byteoffset+self._itemsize])) def _setitem(self, key, value): """_getitem(self, byteoffset) sets 'byteoffset' to result of "padding" 'value'. _setitem silently truncates inputs which are too long. >>> s=array([""]) >>> s[0] = "this" >>> s CharArray(['']) >>> s=array(["this","that"]) >>> s[0] = "othe" >>> s CharArray(['othe', 'that']) >>> s[1] = "v" >>> s CharArray(['othe', 'v']) >>> s = array("") >>> s[0] = "this" >>> s CharArray(['']) """ bo = self._getByteOffset(key) self._data[bo:bo+self._itemsize] = self.pad(value)[0:self._itemsize] def _byteView(self): """_byteView(self) returns a view of self as an array of bytes. A _byteView cannot be taken from a chararray with itemsize==0. """ if self._itemsize == 0: raise ValueError("_byteView doesn't work for zero length items.") b = numarray.NumArray(buffer=self._data, shape=self._shape+(self._itemsize,), type=numarray.UInt8, byteoffset=self._byteoffset, bytestride=self._bytestride) b._strides = self._strides + (1,) return b; def _copyFrom(self, arr, subShape=None, offset=None): """ >>> c = array([""]) >>> c[:] = array(["this"]) >>> c CharArray(['']) >>> c = array(["this","that"]) >>> c[:] = array(["a really long line","a"]) >>> c CharArray(['a re', 'a']) >>> c[:] = ["more","money"] >>> c CharArray(['more', 'mone']) >>> c[:] = array(["x"]) >>> c CharArray(['x', 'x']) """ if self._itemsize == 0: return if subShape is None: assert offset is None subarr = self subShape = self._shape else: assert offset is not None subarr = array(buffer=self._data, shape=subShape, itemsize=self._itemsize, byteoffset=offset, bytestride=self._bytestride, kind = self.__class__) # Convert lists and strings to chararray. arr = inputarray(arr, itemsize=self._itemsize, kind=self.__class__) # Ensure shapes match. arr = subarr._broadcast( arr, raiseOnFail=1) if arr._itemsize == 0: return # Get views of both source and destination as UInt8 arrays. it = arr._byteView() me = subarr._byteView() if self._itemsize <= arr._itemsize: me[:] = it[..., :self._itemsize] else: me[...,:it._shape[-1]] = it # zero fill the part of subarr *not* covered by arr me[...,it._shape[-1]:] = 0 def _concatenate(self, other): """ _concatenate(self, other) implements chararray's low level concatenation policy on shape matched chararrays. >>> array(["this", "that", "another"]).stripAll() + "." CharArray(['this.', 'that.', 'another.']) >>> array([""])+array([""]) CharArray(['']) """ result = array(buffer=None, shape=self._shape, itemsize=self._itemsize+other._itemsize, kind=self.__class__) return _chararray.Concat( self.contiguous(), other.contiguous().stripAll(), result, self.__class__ is RawCharArray).padAll(); def concatenate(self, other): """concatenate(self, other) concatenates two arrays element by element """ a = inputarray(other, kind=self.__class__) self, a = self._dualbroadcast(a, raiseOnFail = 1) return self._concatenate(a) def __add__(self, other): """ >>> map(str, range(3)) + array(["this","that","another one"]) CharArray(['0this', '1that', '2another one']) >>> "" + array(["this", "that"]) CharArray(['this', 'that']) >>> "prefix with trailing whitespace " + array(["."]) CharArray(['prefix with trailing whitespace .']) >>> "" + array("") CharArray(['']) >>> array(["this", "that", "another one"], kind=RawCharArray) + map(str, range(3)) RawCharArray(['this 0', 'that 1', 'another one2']) """ return self.concatenate(other) def __radd__(self, other): return inputarray(other, kind=self.__class__).concatenate(self) def __iadd__(self, other): self[:] = self.concatenate(other) return self def strip(self, value): return value def pad(self, value): return value def stripAll(self): return self def padAll(self): return self def __repr__(self): return "RawCharArray(" + _charArrayToStringList(self) + ")" def __str__(self): """__str__(self) formats 'self' as a string list. >>> s=fromlist(["This is a test. ", "that is too"]) >>> print s ['This is a test.', 'that is too'] """ return _charArrayToStringList(self) def __cmp__(self, other): s, t = str(self), str(other) return cmp(s,t) def fill(self, char): """fill(self, char) fills the array entirely with 'char'. >>> x=array([""]) >>> x.fill(' ') >>> x CharArray(['']) >>> x=array(["this"]) >>> x.fill("x") >>> x CharArray(['xxxx']) """ self[:] = char*self._itemsize def raw(self): """raw(self) returns a raw view of self. """ arr = _EmptyClass() arr.__class__ = RawCharArray # "Anchor" on RawCharArray. arr.__dict__.update(self.__dict__) return arr def contiguous(self): """contiguous(self) returns a version of self which is guaranteed to be contiguous. If self is contiguous already, it returns self. Otherwise, it returns a copy of self. """ if self.iscontiguous(): return self else: return self.copy() def resized(self, n): """resized(self, n) returns a copy of self, resized so that each item is of length n characters. Extra characters are zero filled. If self._itemsize == n, self is returned. """ if self._itemsize != n: ext = self.__class__(shape=self._shape, itemsize=n) ext.fill(chr(0)) ext[:] = self return ext else: return self # First half of comparison operators def StrCmp(self, b): """StrCmp(self, b) calls strncmp on corresponding items of the two arrays, self and b. """ b = inputarray(b, kind=self.__class__) self, b = self._dualbroadcast(b) if self._itemsize < b._itemsize: self = self.resized(b._itemsize) elif b._itemsize < self._itemsize: b = b.resized(self._itemsize) if self is None: raise ValueError("Incompatible array dimensions") return _chararray.StrCmp(self.contiguous().stripAll(), b.contiguous().stripAll(), numarray.NumArray(shape=self._shape, type=numarray.Int8), self.__class__ is RawCharArray) # rich comparisons (only works in Python 2.1 and later) def __eq__(self, other): """ >>> array(["this ", "thar", "other"]).__eq__(array(["this", "that", "another"])) array([1, 0, 0], type=Bool) >>> array([""]).__eq__(array([""])) array([1], type=Bool) >>> array([""]).__eq__(array(["x"])) array([0], type=Bool) >>> array(["x"]).__eq__(array([""])) array([0], type=Bool) """ return self.StrCmp(other).__eq__(0) def __lt__(self, other): """ >>> s=array(["this ", "thar", "other"]) >>> t=array(["this", "that", "another"]) >>> s.__lt__(t) array([0, 1, 0], type=Bool) """ return self.StrCmp(other).__lt__(0) def __ne__(self, other): """ >>> s=array(["this ", "thar", "other"]) >>> t=array(["this", "that", "another"]) >>> s.__ne__(t) array([0, 1, 1], type=Bool) """ return self.StrCmp(other).__ne__(0) def __le__(self, other): """ >>> s=array(["this ", "thar", "other"]) >>> t=array(["this", "that", "another"]) >>> s.__le__(t) array([1, 1, 0], type=Bool) """ return self.StrCmp(other).__le__(0) def __ge__(self, other): """ >>> s=array(["this ", "thar", "other"]) >>> t=array(["this", "that", "another"]) >>> s.__ge__(t) array([1, 0, 1], type=Bool) """ return self.StrCmp(other).__ge__(0) def __gt__(self, other): """ >>> s=array(["this ", "thar", "other"]) >>> t=array(["this", "that", "another"]) >>> s.__gt__(t) array([0, 0, 1], type=Bool) """ return self.StrCmp(other).__gt__(0) if sys.version_info >= (2,1,0): def _test_rich_comparisons(): """ >>> s=array(["this ", "thar", "other"]) >>> t=array(["this", "that", "another"]) >>> s == t array([1, 0, 0], type=Bool) >>> s < t array([0, 1, 0], type=Bool) >>> s >= t array([1, 0, 1], type=Bool) >>> s <= t array([1, 1, 0], type=Bool) >>> s > t array([0, 0, 1], type=Bool) """ pass def __nonzero__(self): raise "Boolean arrays must be reduced for use in conditional expressions." def __contains__(self, str): """ Returns 1 if-and-only-if 'self' has an element == to 'str' >>> s=array(["this ", "thar", "other"]) >>> "this" in s 1 >>> "tjt" in s 0 >>> x=array([""]) >>> "this" in x 0 >>> "" in x 1 """ return numarray.logical_or.reduce(numarray.ravel(self.__eq__(str))) def sort(self): """ >>> a=fromlist(["other","this","that","another"]) >>> a.sort() >>> a CharArray(['another', 'other', 'that', 'this']) """ l = _tolist(self) l.sort() self[:] = fromlist(l) def argsort(self): """ >>> a=fromlist(["other","that","this","another"]) >>> a.argsort() array([3, 0, 1, 2]) """ ax = range(len(self)) ax.sort(lambda x,y,z=self: cmp(z[x],z[y])) return numarray.array(ax) def amap(self, f): if len(self._shape) == 1: return [f(i) for i in self] else: ans = [] for i in self: ans.append(i.amap(f)) return ans def match(self, r, flags=0): """ >>> a=fromlist([["wo","what"],["wen","erewh"]]) >>> a.match("wh[aebd]") (array([0]), array([1])) >>> a.match("none") (array([], type=Int32), array([], type=Int32)) >>> b=array([""]) >>> b.match("this") (array([], type=Int32),) >>> b.match("") (array([0]),) """ matcher = re.compile(r, flags).match l = lambda x, f=matcher: f(x) is not None matches = numarray.array(self.amap(l), type=numarray.Bool) if len(matches): return numarray.nonzero(matches) else: return () def search(self, r, flags=0): """ >>> a=fromlist([["wo","what"],["wen","erewh"]]) >>> a.search("wh") (array([0, 1]), array([1, 1])) >>> a.search("1") (array([], type=Int32), array([], type=Int32)) >>> b=array(["",""]) >>> b.search("1") (array([], type=Int32),) >>> b.search("") (array([0, 1]),) """ searcher = re.compile(r, flags).search l = lambda x, f=searcher: f(x) is not None matches = numarray.array(self.amap(l), type=numarray.Bool) if len(matches): return numarray.nonzero(matches) else: return () def grep(self, r, flags=0): """ >>> a=fromlist([["who","what"],["when","where"]]) >>> a.grep("whe") CharArray(['when', 'where']) """ return numarray.ndarray._take(self, self.match(r, flags)) def sub(self, pat, rep, flags=0, count=0): """ >>> a=fromlist([["who","what"],["when","where"]]) >>> a.sub("wh", "ph") >>> a CharArray([['pho', 'phat'], ['phen', 'phere']]) """ cpat = re.compile(pat, flags) l = lambda x, p=cpat, r=rep, c=count: re.sub(p, r, x, c) self[:] = fromlist( self.amap(l) ) def tolist(self): """ >>> fromlist(["this","that"]).tolist() ['this', 'that'] """ return _tolist(self) def eval(self): """eval(self) converts CharArray 'self' into a NumArray. >>> array([["1","2"],["3","4"]]).eval() array([[1, 2], [3, 4]]) >>> try: ... array([["1","2"],["3","other"]]).eval() ... except NameError: ... pass """ n = numarray.array([ eval(x,{},{}) for x in numarray.ravel(self)]) n.setshape(self._shape) return n def fasteval(self, globals=None, locals=None, type=numarray.Float64): """fasteval(self) converts CharArray 'self' into a NumArray. >>> array([["1","2"],["3","4"]]).fasteval(type=numarray.Int32) array([[1, 2], [3, 4]]) >>> try: ... array([["1","2"],["3","other"]]).fasteval() ... except _chararray.error: ... pass """ n = numarray.array(shape=self._shape, type=numarray.Float64) _chararray.Eval(self, n, globals or _globals(), locals or _locals()) if type != numarray.Float64: return n.astype(type) else: return n class CharArray(RawCharArray): """ >>> array("thisthatthe othe",shape=(4,),itemsize=4) CharArray(['this', 'that', 'the', 'othe']) >>> array("thisthatthe othe",shape=(4,),itemsize=4)._shape (4,) >>> array("thisthatthe othe",shape=(4,),itemsize=4)._itemsize 4 >>> array([["this","that"],["x","y"]]) CharArray([['this', 'that'], ['x', 'y']]) >>> array([["this","that"],["x","y"]])._shape (2, 2) >>> array([["this","that"],["x","y"]])._itemsize 4 >>> s=array([["this","that"],["x","y"]], itemsize=10) >>> s CharArray([['this', 'that'], ['x', 'y']]) >>> s._itemsize 10 >>> s[0][0] 'this' >>> # s[1,1][0] = 'z' # Char assigment doesn't work! >>> s[1,1] = 'z' # But padding may do what you want. >>> s # Otherwise, specify all of s[1,1] or subclass. CharArray([['this', 'that'], ['x', 'z']]) """ def pad(self, value): """ pad(self, value) implements CharArray's string-filling policy which is used when strings are assigned to elements of a CharArray. Pad extends 'value' to length self._itemsize using spaces. """ return _chararray.Pad(value, self._itemsize) def strip(self, value): """ strip(self, value) implements CharArray's string fetching "cleanup" policy. strip truncates 'value' at the first NULL and removes all trailing whitespace from the remainder. For compatability with FITS, leading whitespace is never completely stripped: a string beginning with a space always returns at least one space to distinguish it from the empty string. """ return _chararray.Strip(value) def stripAll(self): """ stripAll(self) applies the chararray strip function to each element of self and returns the result. The result may be a new array. """ return _chararray.StripAll( self.contiguous() ); def padAll(self): """ padAll(self) applies the chararray pad function to each element of self and returns the result. The result may be a new array. """ return _chararray.PadAll( self.contiguous() ); def maxLen(self): """ maxLen(self) computes the length of the longest string in self. Maxlen will applies the strip function to each element prior to computing its length. >>> array(["this ","that"]).maxLen() 4 """ return _chararray.MaxLen( self.contiguous() ) def truncated(self): """ truncate(self) returns a new array with the smallest possible itemsize which will hold the stripped contents of self. >>> array(["this ","that"])._itemsize 6 >>> array(["this ","that"]).truncated()._itemsize 4 """ return self.resized(self.maxLen()) def __repr__(self): return "CharArray(" + _charArrayToStringList(self) + ")" def isString(s): return isinstance(s, types.StringType) def isPySequence(s): return isinstance(s, types.ListType) or isinstance(s, types.TupleType) def _slistShape0(slist): """_slistShape0(slist) computes the (shape+(itemsize,)) tuple of string list 'slist'. itemsize is set to the maximum of all string lengths in slist. >>> s=["this","that","the other"] >>> _slistShape(s) ((3,), 9) >>> _slistShape((s,s,s,s)) ((4, 3), 9) """ if isString(slist): return (len(slist),) elif not isPySequence(slist): raise TypeError("_slistShape only operates on lists of strings") else: return (len(slist),)+ max([_slistShape0(s) for s in slist]) def _slistShape(slist, itemsize=None, shape=None): """_slistShape(slist, itemsize=None, shape=None) computes the "natural" shape and itemsize of slist, and combines this with the specified itemsize and shape, checking for consistency. Specifying an itemsize overrides the slist's natural itemsize. Specifying a shape checks for consistency against the slist's shape. """ shape_items = _slistShape0(slist) if shape is None: shape = shape_items[:-1] else: if shape != shape_items[:-1]: return ValueError("Inconsistent list and shape") if itemsize is None: itemsize = shape_items[-1] else: pass # specified itemsize => padded extension or silent truncation. return (shape, itemsize) def _pad(slist, n, c=" "): """_pad(slist, n, c=' ') pads each member of string list 'slist' with fill character 'c' to a total length of 'n' characters and returns the concatenated results. strings longer than n are *truncated*. >>> >>> _pad(["this","that","the other"],9," ") 'this that the other' """ if isString(slist): if n > len(slist): return slist + c*(n-len(slist)) else: return slist[:n] else: return string.join([_pad(s,n,c) for s in slist], "") def fromlist(slist, itemsize=None, shape=None, padc=" ", kind=CharArray): """fromlist(slist, padc=" ") creates a CharArray from a multi-dimensional list of strings, 'slist', padding each string to the length of the longest string with character 'padc'. >>> s=fromlist([["this","that"],["x","y"]]) >>> s CharArray([['this', 'that'], ['x', 'y']]) >>> s[0][0] 'this' >>> s[1][1] 'y' >>> s[1][1] = "whom" >>> s[1][1] 'whom' >>> fromlist(['this', 'that'], itemsize=2) CharArray(['th', 'th']) >>> fromlist(['t','u'], itemsize=3) CharArray(['t', 'u']) >>> fromlist(['t','u'], itemsize=3)._itemsize 3 """ slist = list(slist) # convert tuples shape, itemsize = _slistShape(slist, itemsize=itemsize, shape=shape) s = _pad(slist, itemsize, padc) # compute padded concatenation of slist return fromstring(s, shape=shape, itemsize=itemsize, kind=kind) def _stringToBuffer(datastring): """_stringToBuffer(datastring) allocates a buffer, copies datastring into it, and returns the buffer. """ abuff = memory.memory_buffer( len(datastring) ) abuff[:] = datastring return abuff def fromstring(s, itemsize=None, shape=None, kind=CharArray): """Create an array from binary data contained in a string (by copying) >>> fromstring('thisthat', itemsize=4) CharArray(['this', 'that']) >>> fromstring('thisthat', shape=2) CharArray(['this', 'that']) >>> fromstring('this is a test', shape=(1,)) CharArray(['this is a test']) """ if isinstance(shape, types.IntType): shape = (shape,) if ((shape in [None, (1,)]) and (itemsize is not None and itemsize > len(s))): s = _pad(s, itemsize, " ") if shape is None and not itemsize: shape = (1,) itemsize = len(s) return kind(_stringToBuffer(s), shape=shape, itemsize=itemsize) def fromfile(file, itemsize=None, shape=None, kind=CharArray): """Create an array from binary file data If file is a string then that file is opened, else it is assumed to be a file object. No options at the moment, all file positioning must be done prior to this function call with a file object >>> import testdata >>> s=fromfile(testdata.filename, shape=-1, itemsize=80) >>> s[0] 'SIMPLE = T / file does conform to FITS standard' >>> s._shape (108,) >>> s._itemsize 80 """ if isinstance(shape, types.IntType): shape = (shape,) name = 0 if isString(file): name = 1 file = open(file, 'rb') size = int(os.path.getsize(file.name) - file.tell()) if not shape and not itemsize: shape = (1,) itemsize = size elif shape is not None: if itemsize is not None: shapesize = numarray.product(shape)*itemsize if shapesize < 0: shape = list(shape) shape[ shape.index(-1) ] = size / -shapesize shape = tuple(shape) else: shapesize=numarray.product(shape) if shapesize < 0: raise ValueError("Shape dimension of -1 requires itemsize.") itemsize = size / shapesize elif itemsize: shape = (size/itemsize,) else: raise ValueError("Must define shape or itemsize.") nbytes = numarray.product(shape)*itemsize if nbytes > size: raise ValueError( "Not enough bytes left in file for specified shape and type") # create the array arr = kind(None, shape=shape, itemsize=itemsize) nbytesread = memory.file_readinto(file, arr._data) if nbytesread != nbytes: raise IOError("Didn't read as many bytes as expected") if name: file.close() return arr def array(buffer=None, itemsize=None, shape=None, byteoffset=0, bytestride=None, kind=CharArray): """array(buffer=None, itemsize=None, shape=None) creates a new instance of a CharArray. buffer specifies the source of the array's initialization data. type(buffer) is in [ None, CharArray, StringType, ListType, FileType, BufferType]. itemsize specifies the fixed maximum length of the array's strings. shape specifies the array dimensions. >>> array(None,itemsize=3,shape=(1,)) CharArray([' ']) >>> array(buffer("abcdsedxxxxxncxn"), itemsize=2, byteoffset=4, bytestride=8) CharArray(['se', 'nc']) >>> array("abcd", itemsize=2) CharArray(['ab', 'cd']) >>> array(['this', 'that'], itemsize=10) CharArray(['this', 'that']) >>> array(['this', 'that'], itemsize=10)._itemsize 10 >>> array(array(['this', 'that'], itemsize=10)) CharArray(['this', 'that']) >>> import testdata >>> array(open(testdata.filename,"r"),itemsize=80, shape=2) CharArray(['SIMPLE = T / file does conform to FITS standard', 'BITPIX = 16 / number of bits per data pixel']) """ if isinstance(shape, types.IntType): shape = (shape,) if buffer is None or numarray.SuitableBuffer(buffer): return kind(buffer, itemsize=itemsize, shape=shape, byteoffset=byteoffset, bytestride=bytestride) if byteoffset or bytestride is not None: raise ValueError('Offset and stride can only be specified if "buffer" is a buffer or None') if isString(buffer): return fromstring(buffer, itemsize=itemsize, shape=shape, kind=kind) elif isPySequence(buffer): return fromlist(buffer, itemsize=itemsize, shape=shape, kind=kind) elif isinstance(buffer, kind) and buffer.__class__ is kind: return buffer.copy() elif isinstance(buffer, RawCharArray): return kind(buffer=buffer._data, itemsize=itemsize or buffer._itemsize, shape=shape or buffer._shape) elif isinstance(buffer, types.FileType): return fromfile(buffer, itemsize=itemsize, shape=shape, kind=kind) else: raise TypeError("Don't know how to handle that kind of buffer") def inputarray(buffer=None, itemsize=None, shape=None, byteoffset=0, bytestride=None, kind=CharArray): """inputarray(buffer=None, itemsize=None, shape=None, byteoffset=0, bytestride=None, kind=CharArray) is used to massage the inputs of a function into a chararray. If buffer is *already* a chararray of the appropriate kind, it is returned unaltered. """ if isinstance(buffer, kind) and buffer.__class__ is kind: return buffer else: return array(buffer, itemsize, shape, byteoffset, bytestride, kind) def _bufferItems(buffer, offset=0, bytestride=None, itemsize=None): """ >>> _bufferItems(buffer("0123456789"), offset=2, bytestride=4, itemsize=1) 2 >>> _bufferItems(buffer("0123456789"), offset=1, bytestride=2, itemsize=1) 5 >>> _bufferItems(buffer("0123456789"), bytestride=5, itemsize=2) 2 >>> _bufferItems(buffer("0123456789"), bytestride=None, itemsize=2) 5 >>> _bufferItems(buffer("0123456789"), offset=3) 7 >>> _bufferItems(buffer("abcdsedxxxxxncxn"),itemsize=2,offset=4,bytestride=8) 2 >>> cc=CharArray(buffer('abcdef'*5),shape=(2,),itemsize=2,byteoffset=8,bytestride=20,aligned=0) >>> cc CharArray(['cd', 'ef']) """ if bytestride is None: if itemsize is None: return len(buffer) - offset else: if itemsize: return (len(buffer)-offset)/itemsize else: return 1 # Hack to permit 0 length strings else: if itemsize is None: raise ValueError("Must specify itemsize if bytestride is specified.") strides = (len(buffer)-offset)*1.0/bytestride istrides = int(strides) fstrides = int((strides-istrides)*bytestride+0.5) return istrides + (fstrides >= itemsize) def _charArrayToStringList(ca): if len(ca._shape) == 1: return str([ str(x) for x in ca]) else: rs = [ _charArrayToStringList(ni) for ni in ca ] return "[" + string.join(rs,", ") + "]" def _tolist(ca): if len(ca._shape) == 1: return [ x for x in ca ] else: return [ _tolist(ni) for ni in ca ] def num2char(num, format, itemsize=32): """num2char formats NumArray 'num' into a CharArray using 'format' >>> num2char(numarray.arange(0.0,5), '%2.2f') CharArray(['0.00', '1.00', '2.00', '3.00', '4.00']) >>> num2char(numarray.arange(0.0,5), '%d') CharArray(['0', '1', '2', '3', '4']) """ wnum = (((num.type() == numarray.Float64) and num) or num.astype(numarray.Float64)) char = CharArray(shape=num.getshape(), itemsize=itemsize) _chararray.Format(char, format, wnum) return char def isntprivate(prefix, base): return 0 def test(): import doctest, chararray return doctest.testmod(chararray, isprivate=isntprivate) if __name__ == "__main__": test()