Display an ASCII Table in Python - python

I want to display an ASCII table of the characters from 32 to 127 (decimal), but instead of the decimal numbers I want it to display the hexadecimal ones with the according characters next to them so it can look like this:
20 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' 28 ( 29 ) 2a * 2b + 2c , 2d - 2e . 2f /
30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 38 8 39 9 3a : 3b ; 3c < 3d = 3e > 3f ?
40 # 41 A 42 B 43 C 44 D 45 E 46 F 47 G 48 H 49 I 4a J 4b K 4c L 4d M 4e N 4f O
50 P 51 Q 52 R 53 S 54 T 55 U 56 V 57 W 58 X 59 Y 5a Z 5b [ 5c \ 5d ] 5e ^ 5f _
60 ` 61 a 62 b 63 c 64 d 65 e 66 f 67 g 68 h 69 i 6a j 6b k 6c l 6d m 6e n 6f o
70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w 78 x 79 y 7a z 7b { 7c | 7d } 7e ~
I need to use a 'for-loop' for this and have 16 characters per row as shown above.
So far I have this as a code, but it prints out the decimal numbers and I don't know how to make it print out the hexadecimal ones, also I don't know how to make the characters stay next to the hexadecimal ones and not above them:
for i in range(32, 127, 16):
for characters in range(i, i+16):
print('%5s'%chr(characters), end="")
print()
for decimal in range(i, i+16):
print('%5s'%decimal, end="")
print()

You can change the format specification; change the s to x (or X if you want uppercase letters in the hexadecimal numbers).
That is
print('%5x' % decimal, end="")

Use %x:
for i in range(32, 127, 16):
for characters in range(i, i+16):
print('%2x %-4s'%(characters, chr(characters)) , end="")
print()

You can also use the new style formatting
>>> '{:x} {:<4}'.format(65, chr(65))
'41 A '
If you uncouple generating the strings from printing you get a little more readable code.
from itertools import islice
# cell generator
cells = (f"{i:x} {chr(i):<4}" for i in range(32, 127))
# cell printer
for _ in range(32, 127, 16):
# for every row print the next 16 cells
print(*islice(cells, 0, 16))

I suggest using the f-string syntax.
for i in range(32, 127, 16):
for characters in range(i, i+16):
print(f"{characters:2x} {chr(characters):<4}", end="")
print()

Related

How to use use numpy random choice to get progressively longer sequences with the same numbers?

What I tried was this:
import numpy as np
def test_random(nr_selections, n, prob):
selected = np.random.choice(n, size=nr_selections, replace= False, p = prob)
print(str(nr_selections) + ': ' + str(selected))
n = 100
prob = np.random.choice(100, n)
prob = prob / np.sum(prob) #only for demonstration purpose
for i in np.arange(10, 100, 10):
np.random.seed(123)
test_random(i, n, prob)
The result was:
10: [68 32 25 54 72 45 96 67 49 40]
20: [68 32 25 54 72 45 96 67 49 40 36 74 46 7 21 20 53 65 89 77]
30: [68 32 25 54 72 45 96 67 49 40 36 74 46 7 21 20 53 62 86 60 35 37 8 48
52 47 31 92 95 56]
40: ...
Contrary to my expectation and hope, the 30 numbers selected do not contain all of the 20 numbers. I also tried using numpy.random.default_rng, but only strayed further away from my desired output. I also simplified the original problem somewhat in the above example. Any help would be greatly appreciated. Thank you!
Edit for clarification: I do not want to generate all the sequences in one loop (like in the example above) but rather use the related sequences in different runs of the same program. (Ideally, without storing them somewhere)

python 3 - having issues with strings of this type -> "ss:seconds:3\x01"

I would figure the "\x01" as part of a string would be ignored but guess not. How so I resolve so I print and use as intended? As a string
Thanks
key_hash = {}
key_hash["ss:seconds:3\x01"] = "topic-1"
key_hash["ss:seconds:3\x02"] = "topic-2"
key_hash["ss:seconds:3\x03"] = "topic-3"
key_hash["ss:seconds:3\x04"] = "topic-4"
for key,topic in key_hash.items():
print(key,topic)
Here is the output:
ss:seconds:3 topic-1
ss:seconds:3 topic-2
ss:seconds:3 topic-3
ss:seconds:3 topic-4
But I want
ss:seconds:3\x01 topic-1
They are not ignored, but your terminal displays all 4 control characters as zero-width glyphs. On my terminal (with the control characters in the output of hexdump emphasized):
$ python3 tmp.py
ss:seconds:3 topic-1
ss:seconds:3 topic-2
ss:seconds:3 topic-3
ss:seconds:3 topic-4
$ python3 tmp.py | hexdump -C
00000000 73 73 3a 73 65 63 6f 6e 64 73 3a 33 01 20 74 6f |ss:seconds:3. to|
00000010 70 69 63 2d 31 0a 73 73 3a 73 65 63 6f 6e 64 73 |pic-1.ss:seconds|
00000020 3a 33 02 20 74 6f 70 69 63 2d 32 0a 73 73 3a 73 |:3. topic-2.ss:s|
00000030 65 63 6f 6e 64 73 3a 33 03 20 74 6f 70 69 63 2d |econds:3. topic-|
00000040 33 0a 73 73 3a 73 65 63 6f 6e 64 73 3a 33 04 20 |3.ss:seconds:3. |
00000050 74 6f 70 69 63 2d 34 0a |topic-4.|
00000058
The problem you run into is that your text contains a hex-letter that is not printable: \x01 is one letter (see f.e on ascii-code.com).
You can see this when you check the strings lenght:
text = "ss:seconds:3\x01"
print('+' + text + '+') # on my console: +ss:seconds:3+
print(text, len(text))
1234567890123
ss:seconds:3* 13 # * is the non printable character \x01
You can (artificially) change the string to contain the hex representation for all non-printable characters like so:
from string import printable
def change_non_printables(text):
p = set(printable)
return ''.join((t if t in p else fr"\x{ord(t):02x}" for t in text))
modified = change_non_printables(text)
print(modified)
to output:
ss:seconds:3\x01
which you then could use as key in your dict.
You could use raw string if I'm right.
key_hash = {}
key_hash[r"ss:seconds:3\x01"] = "topic-1"
key_hash[r"ss:seconds:3\x02"] = "topic-2"
key_hash[r"ss:seconds:3\x03"] = "topic-3"
key_hash[r"ss:seconds:3\x04"] = "topic-4"
for key,topic in key_hash.items():
print(key,topic)
I got the output as
ss:seconds:3\x01 topic-1
ss:seconds:3\x02 topic-2
ss:seconds:3\x03 topic-3
ss:seconds:3\x04 topic-4

how to print unicode number series in python?

I am just trying to print the Unicode number ranging from 1 to 100 in python. I have searched a lot in StackOverflow but no question answers my queries.
So basically I want to print Bengali numbers from ১ to ১০০. The corresponding English number is 1 to 100.
What I have tried is to get the Unicode number of ১ which is '\u09E7'. Then I have tried to increase this number by 1 as depicted in the following code:
x = '\u09E7'
print(x+1)
But the above code says to me the following output.
TypeError: can only concatenate str (not "int") to str
So what I want is to get a number series as following:
১, ২, ৩, ৪, ৫, ৬, ৭, ৮, ৯, ১০, ১১, ১২, ১৩, ............, ১০০
TypeError: can only concatenate str (not "int") to str1
I wish if there is any solution to this. Thank you.
Make a translation table. The function str.maketrans() takes a string of characters and a string of replacements and builds a translation dictionary of Unicode ordinals to Unicode ordinals. Then, convert a counter variable to a string and use the translate() function on the result to convert the string:
#coding:utf8
xlat = str.maketrans('0123456789','০১২৩৪৫৬৭৮৯')
for i in range(1,101):
print(f'{i:3d} {str(i).translate(xlat)}',end=' ')
Output:
1 ১ 2 ২ 3 ৩ 4 ৪ 5 ৫ 6 ৬ 7 ৭ 8 ৮ 9 ৯ 10 ১০ 11 ১১ 12 ১২ 13 ১৩ 14 ১৪ 15 ১৫ 16 ১৬ 17 ১৭ 18 ১৮ 19 ১৯ 20 ২০ 21 ২১ 22 ২২ 23 ২৩ 24 ২৪ 25 ২৫ 26 ২৬ 27 ২৭ 28 ২৮ 29 ২৯ 30 ৩০ 31 ৩১ 32 ৩২ 33 ৩৩ 34 ৩৪ 35 ৩৫ 36 ৩৬ 37 ৩৭ 38 ৩৮ 39 ৩৯ 40 ৪০ 41 ৪১ 42 ৪২ 43 ৪৩ 44 ৪৪ 45 ৪৫ 46 ৪৬ 47 ৪৭ 48 ৪৮ 49 ৪৯ 50 ৫০ 51 ৫১ 52 ৫২ 53 ৫৩ 54 ৫৪ 55 ৫৫ 56 ৫৬ 57 ৫৭ 58 ৫৮ 59 ৫৯ 60 ৬০ 61 ৬১ 62 ৬২ 63 ৬৩ 64 ৬৪ 65 ৬৫ 66 ৬৬ 67 ৬৭ 68 ৬৮ 69 ৬৯ 70 ৭০ 71 ৭১ 72 ৭২ 73 ৭৩ 74 ৭৪ 75 ৭৫ 76 ৭৬ 77 ৭৭ 78 ৭৮ 79 ৭৯ 80 ৮০ 81 ৮১ 82 ৮২ 83 ৮৩ 84 ৮৪ 85 ৮৫ 86 ৮৬ 87 ৮৭ 88 ৮৮ 89 ৮৯ 90 ৯০ 91 ৯১ 92 ৯২ 93 ৯৩ 94 ৯৪ 95 ৯৫ 96 ৯৬ 97 ৯৭ 98 ৯৮ 99 ৯৯ 100 ১০০
You can try this. Convert the character to an integer. Do the addition and the convert it to character again. If the number is bigger than 10 you have to convert both digits to characters that's why we are using modulo %.
if num < 10:
x = ord('\u09E6')
print(chr(x+num))
elif num < 100:
mod = num % 10
num = int((num -mod) / 10)
x = ord('\u09E6')
print(''.join([chr(x+num), chr(x+mod)]))
else:
x = ord('\u09E6')
print(''.join([chr(x+1), '\u09E6', '\u09E6']))
You can try running it here
https://repl.it/repls/GloomyBewitchedMultitasking
EDIT:
Providing also javascript code as asked in comments.
function getAsciiNum(num){
zero = "০".charCodeAt(0)
if (num < 10){
return(String.fromCharCode(zero+num))
}
else if (num < 100) {
mod = num % 10
num = Math.floor((num -mod) / 10)
return(String.fromCharCode(zero+num) + String.fromCharCode(zero+mod))
}
else {
return(String.fromCharCode(zero+1) + "০০")
}
}
console.log(getAsciiNum(88))

Rot18, encrypt and decrypt (python, Sublime Text)

I am looking for a plugin that can encrypt/decrypt text using rot18 in Sublime Text v3.2.2.
I tried this tutorial (only rot13) but it doesn’t work for me: https://www.sublimetext.com/docs/plugin-examples
I tried a lot of plugins and the only one that works fine is:
(unfortunately it is rot47)
import sublime
import sublime_plugin
class Rot47Command(sublime_plugin.TextCommand):
def run(self, edit):
for region in self.view.sel():
if not region.empty():
s = self.view.substr(region)
s = ''.join(chr(33 + ((ord(ch) + 14) % 94)) for ch in s)
self.view.replace(edit, region, s)
Does anyone have any functional plugin on rot18, please?
You can adapt your code. Here is how rot_N works:
This is the ASCII-Range up to 127:
a = 32
for k in range(0,16):
print(a+k, chr(a+k), " ", a+16+k, chr(a+16+k), " ", a+32+k, chr(a+32+k), " ",
a+48+k, chr(a+48+k), " ", a+64+k, chr(a+64+k), " ", a+80+k, chr(a+80+k))
# 32 48 0 64 # 80 P 96 ` 112 p
# 33 ! 49 1 65 A 81 Q 97 a 113 q
# 34 " 50 2 66 B 82 R 98 b 114 r
# 35 # 51 3 67 C 83 S 99 c 115 s
# 36 $ 52 4 68 D 84 T 100 d 116 t
# 37 % 53 5 69 E 85 U 101 e 117 u
# 38 & 54 6 70 F 86 V 102 f 118 v
# 39 ' 55 7 71 G 87 W 103 g 119 w
# 40 ( 56 8 72 H 88 X 104 h 120 x
# 41 ) 57 9 73 I 89 Y 105 i 121 y
# 42 * 58 : 74 J 90 Z 106 j 122 z
# 43 + 59 ; 75 K 91 [ 107 k 123 {
# 44 , 60 < 76 L 92 \ 108 l 124 |
# 45 - 61 = 77 M 93 ] 109 m 125 }
# 46 . 62 > 78 N 94 ^ 110 n 126 ~
# 47 / 63 ? 79 O 95 _ 111 o 127
ROT n means you take the chr(ord(l)+n)'s letter instead. You need to be carefull when wrapping around.
For calculation of rot_N the basic formular is:
def rot_N(n,letter):
return chr( (ord(letter)-32+n) % (128-32) + 32) # 128-32 = 96
You can test it with:
k="Hello Zzzzz"
print( ''.join(rot_N(18, l) for l in k)) # schould give you a tranlation
print( ''.join(rot_N(0, l) for l in k)) # should give the exact text
and test the inverse with:
k_inverse ="Zw~~!2l,,,,"
print( ''.join(rot_N(-18, l) for l in k_inverse)) # use -18 here
print( ''.join(rot_N(0, l) for l in k_inverse))
If you replace
s = ''.join(chr(33 + ((ord(ch) + 14) % 94)) for ch in s)
with
s = ''.join(rot_N(18, ch) for ch in s))
you should be fine.
You do not specify, but I assume you are using ROT-18 on the character set 0..9, A..Z which is 36 characters. 36/2 = 18, hence ROT-18.
ROT-13 works on the 26 alphabetic characters: 26/2 = 13. You want to adapt that to ROT-18.
The major difference is that the alphabetic characters are continuous in the ASCII character set, and that assumption is built into the code you are copying from. The same is true for ROT-47; the ASCII characters used are continuous. With ROT-18, the digits 0..9 and the alphabetic characters, A..Z are not continuous in ASCII. There is a gap between them from : (#58) to # (#64). ASCII codes in that region are neither digits nor letters.
One solution is to set up your own array, not in the ASCII order, where the two are continuous: [0, 1, ... 9, A, B, ... Z]. Write your program to work on that array.
Alternatively you can work with the ASCII codes, treating codes from #58 to #64 specially to make the shift come out right.
The first option is probably easier, and the code will be more similar to the ROT-13 example. The main difference will be replacing the ord() function, which returns the ASCII code, with an equivalent function giving the position in your array.

Python binary data reading

A urllib2 request receives binary response as below:
00 00 00 01 00 04 41 4D 54 44 00 00 00 00 02 41
97 33 33 41 99 5C 29 41 90 3D 71 41 91 D7 0A 47
0F C6 14 00 00 01 16 6A E0 68 80 41 93 B4 05 41
97 1E B8 41 90 7A E1 41 96 8F 57 46 E6 2E 80 00
00 01 16 7A 53 7C 80 FF FF
Its structure is:
DATA, TYPE, DESCRIPTION
00 00 00 01, 4 bytes, Symbol Count =1
00 04, 2 bytes, Symbol Length = 4
41 4D 54 44, 6 bytes, Symbol = AMTD
00, 1 byte, Error code = 0 (OK)
00 00 00 02, 4 bytes, Bar Count = 2
FIRST BAR
41 97 33 33, 4 bytes, Close = 18.90
41 99 5C 29, 4 bytes, High = 19.17
41 90 3D 71, 4 bytes, Low = 18.03
41 91 D7 0A, 4 bytes, Open = 18.23
47 0F C6 14, 4 bytes, Volume = 3,680,608
00 00 01 16 6A E0 68 80, 8 bytes, Timestamp = November 23,2007
SECOND BAR
41 93 B4 05, 4 bytes, Close = 18.4629
41 97 1E B8, 4 bytes, High = 18.89
41 90 7A E1, 4 bytes, Low = 18.06
41 96 8F 57, 4 bytes, Open = 18.82
46 E6 2E 80, 4 bytes, Volume = 2,946,325
00 00 01 16 7A 53 7C 80, 8 bytes, Timestamp = November 26,2007
TERMINATOR
FF FF, 2 bytes,
How to read binary data like this?
Thanks in advance.
Update:
I tried struct module on first 6 bytes with following code:
struct.unpack('ih', response.read(6))
(16777216, 1024)
But it should output (1, 4). I take a look at the manual but have no clue what was wrong.
So here's my best shot at interpreting the data you're giving...:
import datetime
import struct
class Printable(object):
specials = ()
def __str__(self):
resultlines = []
for pair in self.__dict__.items():
if pair[0] in self.specials: continue
resultlines.append('%10s %s' % pair)
return '\n'.join(resultlines)
head_fmt = '>IH6sBH'
head_struct = struct.Struct(head_fmt)
class Header(Printable):
specials = ('bars',)
def __init__(self, symbol_count, symbol_length,
symbol, error_code, bar_count):
self.__dict__.update(locals())
self.bars = []
del self.self
bar_fmt = '>5fQ'
bar_struct = struct.Struct(bar_fmt)
class Bar(Printable):
specials = ('header',)
def __init__(self, header, close, high, low,
open, volume, timestamp):
self.__dict__.update(locals())
self.header.bars.append(self)
del self.self
self.timestamp /= 1000.0
self.timestamp = datetime.date.fromtimestamp(self.timestamp)
def showdata(data):
terminator = '\xff' * 2
assert data[-2:] == terminator
head_data = head_struct.unpack(data[:head_struct.size])
try:
assert head_data[4] * bar_struct.size + head_struct.size == \
len(data) - len(terminator)
except AssertionError:
print 'data length is %d' % len(data)
print 'head struct size is %d' % head_struct.size
print 'bar struct size is %d' % bar_struct.size
print 'number of bars is %d' % head_data[4]
print 'head data:', head_data
print 'terminator:', terminator
print 'so, something is wrong, since',
print head_data[4] * bar_struct.size + head_struct.size, '!=',
print len(data) - len(terminator)
raise
head = Header(*head_data)
for i in range(head.bar_count):
bar_substr = data[head_struct.size + i * bar_struct.size:
head_struct.size + (i+1) * bar_struct.size]
bar_data = bar_struct.unpack(bar_substr)
Bar(head, *bar_data)
assert len(head.bars) == head.bar_count
print head
for i, x in enumerate(head.bars):
print 'Bar #%s' % i
print x
datas = '''
00 00 00 01 00 04 41 4D 54 44 00 00 00 00 02 41
97 33 33 41 99 5C 29 41 90 3D 71 41 91 D7 0A 47
0F C6 14 00 00 01 16 6A E0 68 80 41 93 B4 05 41
97 1E B8 41 90 7A E1 41 96 8F 57 46 E6 2E 80 00
00 01 16 7A 53 7C 80 FF FF
'''
data = ''.join(chr(int(x, 16)) for x in datas.split())
showdata(data)
this emits:
symbol_count 1
bar_count 2
symbol AMTD
error_code 0
symbol_length 4
Bar #0
volume 36806.078125
timestamp 2007-11-22
high 19.1700000763
low 18.0300006866
close 18.8999996185
open 18.2299995422
Bar #1
volume 29463.25
timestamp 2007-11-25
high 18.8899993896
low 18.0599994659
close 18.4629001617
open 18.8199901581
...which seems to be pretty close to what you want, net of some output formatting details. Hope this helps!-)
>>> data
'\x00\x00\x00\x01\x00\x04AMTD\x00\x00\x00\x00\x02A\x9733A\x99\\)A\x90=qA\x91\xd7\nG\x0f\xc6\x14\x00\x00\x01\x16j\xe0h\x80A\x93\xb4\x05A\x97\x1e\xb8A\x90z\xe1A\x96\x8fWF\xe6.\x80\x00\x00\x01\x16zS|\x80\xff\xff'
>>> from struct import unpack, calcsize
>>> scount, slength = unpack("!IH", data[:6])
>>> assert scount == 1
>>> symbol, error_code = unpack("!%dsb" % slength, data[6:6+slength+1])
>>> assert error_code == 0
>>> symbol
'AMTD'
>>> bar_count = unpack("!I", data[6+slength+1:6+slength+1+4])
>>> bar_count
(2,)
>>> bar_format = "!5fQ"
>>> from collections import namedtuple
>>> Bar = namedtuple("Bar", "Close High Low Open Volume Timestamp")
>>> b = Bar(*unpack(bar_format, data[6+slength+1+4:6+slength+1+4+calcsize(bar_format)]))
>>> b
Bar(Close=18.899999618530273, High=19.170000076293945, Low=18.030000686645508, Open=18.229999542236328, Volume=36806.078125, Timestamp=1195794000000L)
>>> import time
>>> time.ctime(b.Timestamp//1000)
'Fri Nov 23 08:00:00 2007'
>>> int(b.Volume*100 + 0.5)
3680608
>>> struct.unpack('ih', response.read(6))
(16777216, 1024)
You are unpacking big-endian data on a little-endian machine. Try this instead:
>>> struct.unpack('!IH', response.read(6))
(1L, 4)
This tells unpack to consider the data in network-order (big-endian). Also, the values of counts and lengths can not be negative, so you should should use the unsigned variants in your format string.
Take a look at the struct.unpack in the struct module.
Use pack/unpack functions from "struct" package. More info here http://docs.python.org/library/struct.html
Bye!
As it was already mentioned, struct is the module you need to use.
Please read its documentation to learn about byte ordering, etc.
In your example you need to do the following (as your data is big-endian and unsigned):
>>> import struct
>>> x = '\x00\x00\x00\x01\x00\x04'
>>> struct.unpack('>IH', x)
(1, 4)

Categories

Resources