|
| 1 | +# -*- coding: UTF-8 -*- |
| 2 | +"""Letters Codec - letter indices-related content encoding. |
| 3 | +
|
| 4 | +This codec: |
| 5 | +- en/decodes strings from str to str |
| 6 | +- en/decodes strings from bytes to bytes |
| 7 | +- decodes file content to str (read) |
| 8 | +- encodes file content from str to bytes (write) |
| 9 | +""" |
| 10 | +from string import ascii_uppercase |
| 11 | + |
| 12 | +from ..__common__ import * |
| 13 | + |
| 14 | + |
| 15 | +__examples__ = { |
| 16 | + 'enc(consonant-index|consonants_indices)': { |
| 17 | + 'This is a test': "166I15I15A16E1516", |
| 18 | + '\x00': None, |
| 19 | + '\xff': None, |
| 20 | + }, |
| 21 | + 'dec(consonant-index|consonants_indices)': { |
| 22 | + '166I15I15A16E1516': "THISISATEST", |
| 23 | + '\x00': None, |
| 24 | + '\xff': None, |
| 25 | + }, |
| 26 | + 'enc(vowel-index|vowels_indices)': {'This is a test': "TH3S3S1T2ST"}, |
| 27 | + 'dec(vowel-index|vowels_indices)': {'TH3S3S1T2ST': "THISISATEST"}, |
| 28 | + 'enc(consonant-vowel_indices)': {'This is a test': "C16C6V3C15V3C15V1C16V2C15C16"}, |
| 29 | + 'dec(consonants_vowels-index)': {'C16C6V3C15V3C15V1C16V2C15C16': "THISISATEST"}, |
| 30 | +} |
| 31 | + |
| 32 | + |
| 33 | +VOWELS = "AEIOUY" |
| 34 | + |
| 35 | + |
| 36 | +def __get_encmap(letters): |
| 37 | + if re.match(r"^consonants?$", letters): |
| 38 | + encmap = {c: str(i+1) for i, c in enumerate(sorted(set(ascii_uppercase) - set(VOWELS)))} |
| 39 | + for c in VOWELS: |
| 40 | + encmap[c] = c |
| 41 | + elif re.match(r"^vowels?$", letters): |
| 42 | + encmap = {c: c for c in ascii_uppercase} |
| 43 | + for i, c in enumerate(VOWELS): |
| 44 | + encmap[c] = str(i+1) |
| 45 | + elif re.match(r"^consonants?[-_]vowels?$", letters): |
| 46 | + encmap = {c: "C" + str(i+1) for i, c in enumerate(sorted(set(ascii_uppercase) - set(VOWELS)))} |
| 47 | + for i, c in enumerate(VOWELS): |
| 48 | + encmap[c] = "V" + str(i+1) |
| 49 | + for c in " ": |
| 50 | + encmap[c] = "" |
| 51 | + return encmap |
| 52 | + |
| 53 | + |
| 54 | +def letters_encode(letters): |
| 55 | + encmap = __get_encmap(letters) |
| 56 | + def encode(text, errors="strict"): |
| 57 | + s = "" |
| 58 | + for i, c in enumerate(text.upper()): |
| 59 | + try: |
| 60 | + s += encmap[c] |
| 61 | + except KeyError: |
| 62 | + s += handle_error(letters + "_indices", errors)(c, i) |
| 63 | + return "".join(encmap.get(c.upper(), c) for c in text), len(text) |
| 64 | + return encode |
| 65 | + |
| 66 | + |
| 67 | +def letters_decode(letters): |
| 68 | + decmap = {v: k for k, v in __get_encmap(letters).items()} |
| 69 | + maxlen = max(len(x) for x in decmap.keys()) |
| 70 | + def decode(text, errors="strict"): |
| 71 | + s, i = "", 0 |
| 72 | + while i < len(text): |
| 73 | + err = True |
| 74 | + for j in range(maxlen, 0, -1): |
| 75 | + try: |
| 76 | + s += decmap[text[i:i+j]] |
| 77 | + i += j |
| 78 | + err = False |
| 79 | + break |
| 80 | + except (IndexError, KeyError): |
| 81 | + pass |
| 82 | + if err: |
| 83 | + s += handle_error(letters + "_indices", errors, decode=True)(text[i], i) |
| 84 | + return s, len(text) |
| 85 | + return decode |
| 86 | + |
| 87 | + |
| 88 | +add("letter-indices", letters_encode, letters_decode, |
| 89 | + pattern=r"^(consonants?|vowels?|consonants?[-_]vowels?)[-_]ind(?:ex|ices)$") |
| 90 | + |
0 commit comments