#!/usr/bin/env python3 import itertools import sys def decimal_to_alphabet(n: int, alphabet: str) -> str: if n == 0: return alphabet[0] base = len(alphabet) digits = [] while n: digits.append(alphabet[n % base]) n //= base return ''.join(digits[::-1]) def alphabet_to_decimal(s: str, alphabet: str) -> int: base = len(alphabet) l = len(s) return sum(alphabet.index(s[l - 1 - i]) * base ** i for i in range(l)) def test(): assert alphabet_to_decimal('ff', '0123456789abcdef') == 255 assert alphabet_to_decimal('100', '0123456789abcdef') == 256 assert decimal_to_alphabet(255, '0123456789abcdef') == 'ff' assert decimal_to_alphabet(256, '0123456789abcdef') == '100' assert decimal_to_alphabet(0, '0123456789') == '0' def convert_start_stop(s, alphabet): if ':' in s: valalphabet, value = s.split(':') if not valalphabet: valalphabet = '0123456789' else: valalphabet, value = alphabet, s return alphabet_to_decimal(value, valalphabet) if __name__ == '__main__': if len(sys.argv) == 2 and sys.argv[1] == '--test': test() elif len(sys.argv) in (3, 4): if len(sys.argv) == 3: sys.argv.append(sys.argv[-1]) alphabet = sys.argv[1] start, stop = map(lambda x: convert_start_stop(x, alphabet), sys.argv[2:]) for i in range(start, stop + 1): try: sys.stdout.write(decimal_to_alphabet(i, alphabet) + '\n') except (BrokenPipeError, IOError): try: sys.stdout.close() except IOError: pass break else: print('Usage: alphabetseq ALPHABET START [STOP]', file = sys.stderr) print('Generates the sequence from START to STOP (inclusive) using ALPHABET', file = sys.stderr) print('If STOP is omitted, it defaults to START, effectively making this a simple base transformation', file = sys.stderr) print('START and STOP have values of the form [[VALALPHABET]:]VALUE.', file = sys.stderr) print(' In the [VALALPHABET]:VALUE form, VALUE is expressed in terms of VALALPHABET, which defaults to 0123456789 (i.e. decimal) if omitted.', file = sys.stderr) print(' In the VALUE form, it is converted using ALPHABET.', file = sys.stderr) sys.exit(1)