<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Jun 5, 2017 at 3:59 PM, Mikhail V <span dir="ltr"><<a href="mailto:mikhailwas@gmail.com" target="_blank">mikhailwas@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">-- classify by "forward/backward" conversion:<br>
    For this time consider only forward, i.e. I copy data from string<br>
to numpy array<br>
<br>
-- classify by " bytes  vs  ordinals ":<br>
<br>
a)  bytes:  If I need raw bytes - in this case e.g.<br>
<br>
  B = bytes(s.encode())<br></blockquote><div><br></div><div>no need to call "bytes" -- encode() returns a bytes object:</div><div><br></div><font face="monospace, monospace">In [1]: s = "this is a simple ascii-only string"<br><br>In [2]: b = s.encode()<br><br>In [3]: type(b)<br><br>Out[3]: bytes<br><br>In [4]: b<br><br>Out[4]: b'this is a simple ascii-only string'<br></font><br> <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
will do it. then I can copy data to array. So currently there are methods<br>
coverings this. If I understand correctly the data extracted corresponds<br>
to utf-??  byte feed, i.e. non-constant byte-length of chars (1 up to<br>
4 bytes per char for<br>
the 'wide' unicode, correct me if I am wrong).<br></blockquote><div><br></div><font face="monospace, monospace">In [5]: s.encode?<br>Docstring:<br>S.encode(encoding='utf-8', errors='strict') -> bytes<br><br></font>So the default is utf-8, but you can set any encoding you want (that python supports)<div><br></div><font face="monospace, monospace"> In [6]: s.encode('utf-16')<br><br>Out[6]: b'\xff\xfet\x00h\x00i\x00s\x00 \x00i\x00s\x00 \x00a\x00 \x00s\x00i\x00m\x00p\x00l\x00e\x00 \x00a\x00s\x00c\x00i\x00i\x00-\x00o\x00n\x00l\x00y\x00 \x00s\x00t\x00r\x00i\x00n\x00g\x00'</font><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
b):  I need *ordinals*<br>
  Yes, I need ordinals, so for the bytes() method, if a Python 3<br>
string contains only<br>
  basic ascii, I can so or so convert to bytes then to integer array<br>
and the length will<br>
  be the same 1byte for each char.<br>
  Although syntactically seen, and with slicing, this will look e.g. like:<br>
<br>
s= "012 abc"<br>
B = bytes(s.encode())  # convert to bytes<br>
k  = len(s)<br>
arr = np.zeros(k,"u1")   # init empty array length k<br>
arr[0:2] = list(B[0:2])<br>
print ("my array: ", arr)<br>
-><br>
my array:  [48 49  0  0  0  0  0]<br></blockquote><div><br></div><div>This can be done more cleanly:</div><div><br></div><font face="monospace, monospace">In [15]: s= "012 abc"<br><br>In [16]: b = s.encode('ascii')<br><br></font></div><div class="gmail_quote"><font face="monospace, monospace"># you want to use the ascii encoding so you don't get utf-8 cruft if there are non-ascii characters<br>#  you could use latin-1 too (Or any other one-byte per char encoding<br><br></font></div><div class="gmail_quote"><font face="monospace, monospace">In [17]: arr = np.fromstring(b, np.uint8)<br># this is using fromstring() to means it's old py definiton - treat teh contenst as bytes</font></div><div class="gmail_quote"><font face="monospace, monospace"># -- it really should be called "frombytes()" </font></div><div class="gmail_quote"><font face="monospace, monospace"># you could also use:</font></div><div class="gmail_quote"><font face="monospace, monospace"><br></font></div><div class="gmail_quote">







<font face="monospace, monospace">In [22]: np.frombuffer(b, dtype=np.uint8)<br>Out[22]: array([48, 49, 50, 32, 97, 98, 99], dtype=uint8)In [18]: print arr<br><br>In [19]: print(arr)<br>[48 49 50 32 97 98 99]<br><br># you got the ordinals<br><br>In [20]: "".join([chr(i) for i in arr])<br>Out[20]: '012 abc'</font><div><br></div><div># yes, they are the right ones...</div><div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Result seems correct. Note that I also need to use list(B), otherwise<br>
the slicing does not work (fills both values with 1, no idea where 1<br>
comes from).<br></blockquote><div><br></div><div>that is odd -- I can't explain it right now either...</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Or I can write e.g.:<br>
arr[0:2] = np.fromstring(B[0:2], "u1")<br>
<br>
But looks indeed like a 'hack' and not so simple.<br></blockquote><div><br></div><div>is the above OK?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">-- classify "what is maximal ordinal value in the string"<br>
Well, say, I don't know what is maximal ordinal, e.g. here I take<br>
3 Cyrillic letters instead of 'abc':<br>
<br>
s= "012 АБВ"<br>
k  = len(s)<br>
arr = np.zeros(k,"u4")   # init empty 32 bit array length k<br>
arr[:] = np.fromstring(np.array(s),"u4"<wbr>)<br>
-><br>
[  48   49   50   32 1040 1041 1042]<br></blockquote><div><br></div><div>so this is making a numpy string, which is a UCS-4 encoding unicode -- i.e. 4 bytes per charactor. Then you care converting that to an 4-byte unsigned int. but no need to do it with fromstring:</div><div><br></div><div><p class="gmail-p1"><font face="monospace, monospace">In [52]: s<br>Out[52]: '012 АБВ'<br><br>In [53]: s_arr.reshape((1,)).view(np.uint32)<br>Out[53]: array([  48,   49,   50,   32, 1040, 1041, 1042], dtype=uint32)<br><br></font>we need the reshape() because .view does not work with array scalars -- not sure why not? </p></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
This gives correct results indeed. So I get my ordinals as expected.<br>
So this is better/preferred way, right?<br></blockquote><div><br></div><div>I would maybe do it more "directly" -- i.e. use python's string to do the encoding:</div><div><br></div><font face="monospace, monospace">In [64]: s<br>Out[64]: '012 АБВ'<br><br>In [67]: np.fromstring(s.encode('U32'), dtype=np.uint32)<br>Out[67]: array([65279,    48,    49,    50,    32,  1040,  1041,  1042], dtype=uint32)<br><br></font>that first value is the byte-order mark (I think...), you  can strip it off with:</div><div class="gmail_quote"><br><font face="monospace, monospace">In [68]: np.fromstring(s.encode('U32')[4:], dtype=np.uint32)</font><br><font face="monospace, monospace">Out[68]: array([  48,   49,   50,   32, 1040, 1041, 1042], dtype=uint32)</font><br><br>or, probably better simply specify the byte order in the encoding:<br><br><font face="monospace, monospace">In [69]: np.fromstring(s.encode('UTF-32LE'), dtype=np.uint32)</font><br><font face="monospace, monospace">Out[69]: array([  48,   49,   50,   32, 1040, 1041, 1042], dtype=uint32)</font><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">arr = np.ordinals(s)<br>
arr[0:2] = np.ordinals(s[0:2])  # with slicing<br>
<br>
or, e.g. in such format:<br>
<br>
arr = np.copystr(s)<br>
arr[0:2] = np.copystr(s[0:2])<br></blockquote><div><br></div><div>I don't think any of this is necessary -- the UCS4 (Or UTF-32) "encoding" is pretty much the ordinals anyway.</div><div><br></div><div>As you notices, if you make a numpy unicode string array, and change the dtype to unsigned int32, you get what you want.</div><div><br></div><div>You really don't want to mess with any of this unless you understand unicode and encodings anyway....</div><div><br></div><div>Though it is a bit akward -- why is your actual use-case for working with ordinals???</div><div><br></div><div>BTW, you can use regular python to get the ordinals first:</div><div><br></div><font face="monospace, monospace">In [71]: np.array([ord(c) for c in s])<br>Out[71]: array([  48,   49,   50,   32, 1040, 1041, 1042])</font><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Though for Python 2 could raise questions why need casting to "u4".<br></blockquote><div><br></div><div>this would all work the same with python 2 if you used unicode objects instead of strings. Maybe good to put:</div><div><br></div><div>from __future__ import unicode_literals</div><div><br></div><div>in your source....</div><div> <br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">So approximately are my ideas.<br>
For me it would cover many application cases.</blockquote><div><br></div><div>I'm still curious as to your use-cases -- when do you have a bunch of ordinal values??</div><div><br></div><div>-CHB</div><div><br></div><div><br></div></div>-- <br><div class="gmail_signature"><br>Christopher Barker, Ph.D.<br>Oceanographer<br><br>Emergency Response Division<br>NOAA/NOS/OR&R            (206) 526-6959   voice<br>7600 Sand Point Way NE   (206) 526-6329   fax<br>Seattle, WA  98115       (206) 526-6317   main reception<br><br><a href="mailto:Chris.Barker@noaa.gov" target="_blank">Chris.Barker@noaa.gov</a></div>
</div></div>