You want the following ASCII mapping:
a-z
0-18, 19-44, 45-70, 71-96, 97-122, 123-148, 149-174, 175-200, 201-226, 227-252, 253-255
h-z a-z a-z a-z a-z a-z a-z a-z a-z a-z a-c
\--------- 1 -------------------/
\---------------------------- 2 ---------------------------/
For most programming languages (where the sign of the remainder is the sign of the dividend), two different formulas could be used:
For all numbers in the range 0 to 122 use:
r = 122 - ((122 - n) % 26)
For all numbers in the range 97 to 255 use:
r = ((n - 97) % 26) + 97
However, because the remainder does not change if we add a multiple of the divider to the dividend, we can add 4 times 26 and avoid having to deal with a negative dividend altogether.
r = ((n - 97) % 26) + 97
=> r = ((n - 97 + (4 * 26)) % 26) + 97
<=> r = ((n - 97 + 104) % 26) + 97
<=> r = ((n + 7) % 26) + 97 ; This will work no matter how '%' functions
Now in Python, because of how the %
operator functions, we can get by with this one formule:
r = ((n - 97) % 26) + 97
A very fast alternative defines a 256-byte array and then uses the calculated number as an offset in this array, fetching the result at once.
Below is what it could look like in assembly (MASM):
; On input AL register is number n=[0,255]
mov bx, offset array
xlatb
; On output AL register is number r=[97,122] ; ["a","z"]
...
array db 'hijklmnopqrstuvwxyz'
db 9 dup ('abcdefghijklmnopqrstuvwxyz')
db 'abc'
And in Python it becomes
s[n]
with n ranging from 0 to 255 and using a 256-byte string s
s = ("hijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abcdefghijklmnopqrstuvwxyz"
"abc"
)