Functional Weave
Code in Python

encoding.hex@1.0.0

impl/python/hex_decode.py

1,204 bytes · the Python implementation · view raw

from typing import List


def _digit_value(ch: str) -> int:
    # Compared by character range rather than int(ch, 16), which would accept
    # full-width and other scripts' digits that the other languages refuse.
    if "0" <= ch <= "9":
        return ord(ch) - 48
    if "a" <= ch <= "f":
        return ord(ch) - 87
    if "A" <= ch <= "F":
        return ord(ch) - 55
    return -1


def hex_decode(text: str) -> List[int]:
    """Hexadecimal text back to bytes, either case, strictly.

    A 0x prefix, whitespace or an odd digit count is an error, not skipped.
    """
    if not isinstance(text, str):
        raise TypeError("hex text must be a string")
    # Characters are checked before the length, so the answer for non-ASCII
    # input does not depend on how a language counts its length.
    digits = []
    for ch in text:
        d = _digit_value(ch)
        if d < 0:
            raise ValueError("hex text may only contain the digits 0-9, a-f and A-F")
        digits.append(d)
    if len(digits) % 2 != 0:
        raise ValueError("hex text must have an even number of digits, received %d" % len(digits))
    return [digits[i] * 16 + digits[i + 1] for i in range(0, len(digits), 2)]