# deck.xlat: character translation routines with some presets # Usage: from deck import xlat # If there's no preset selected, CYR (cyrillic) gets selected by default # Created by Luxferre in 2025, released into public domain maps = { 'CYR': { 'prefix_chars': ['J', 'X', 'Y', 'j', 'x', 'y'], 'source': '\u0410\u0430\u0411\u0431\u0412\u0432\u0413\u0433\u0490\u0491\u0414\u0434\u0415\u0435\u0404\u0454\u0401\u0451\u0416\u0436\u0417\u0437\u0418\u0438\u0406\u0456\u0407\u0457\u0419\u0439\u041a\u043a\u041b\u043b\u041c\u043c\u041d\u043d\u041e\u043e\u041f\u043f\u0420\u0440\u0421\u0441\u0422\u0442\u0423\u0443\u0424\u0444\u0425\u0445\u0426\u0446\u0427\u0447\u0428\u0448\u0429\u0449\u042a\u044a\u042b\u044b\u042c\u044c\u042d\u044d\u042e\u044e\u042f\u044f', 'mapping': [ 'A', 'a', 'B', 'b', 'W', 'w', 'G', 'g', 'XG', 'xg', 'D', 'd', 'E', 'e', 'JE', 'je', 'JO', 'jo', 'V', 'v', 'Z', 'z', 'I', 'i', 'YI', 'yi', 'JI', 'ji', 'JJ', 'jj', 'K', 'k', 'L', 'l', 'M', 'm', 'N', 'n', 'O', 'o', 'P', 'p', 'R', 'r', 'S', 's', 'T', 't', 'U', 'u', 'F', 'f', 'H', 'h', 'C', 'c', 'XX', 'xx', 'XW', 'xw', 'XQ', 'xq', "x'", "x'", 'YY', 'yy', "'", "'", 'YE', 'ye', 'JU', 'ju', 'Q', 'q' ] } } # generate direct and reverse key-value mappings for mkey, m in maps.items(): maps[mkey]['s2m'] = {} maps[mkey]['m2s'] = {} idx = 0 for char in m['source']: dst = m['mapping'][idx] maps[mkey]['s2m'][char] = dst maps[mkey]['m2s'][dst] = char idx += 1 def enc(s, cmap=None): if cmap == None: cmap = 'CYR' mapobj = maps[cmap] out_str = '' for char in s: if char in mapobj['s2m']: out_str += mapobj['s2m'][char] else: out_str += char return out_str def dec(s, cmap=None): if cmap == None: cmap = 'CYR' mapobj = maps[cmap] prefixes = mapobj['prefix_chars'] m2s = mapobj['m2s'] out_str = '' buf = '' for char in s: if char in prefixes: buf += char else: if buf != '': buf += char else: buf = char if buf in m2s: out_str += m2s[buf] else: out_str += buf buf = '' return out_str