Source code for checkdigit.verhoeff

# /usr/bin/env python

# This file is part of checkdigit.

# checkdigit is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# checkdigit is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with checkdigit.  If not, see <http://www.gnu.org/licenses/>.

"""The first check digit algorithm to detect all transposition and single digit errors.

Developed by Jacobus Verhoeff and published in 1969.
This particular implementation uses a table-based algorithm.
"""

from checkdigit._data import TupleType, cleanse, missing_template

DIHEDRAL_CAYLEY: TupleType[TupleType[int]] = (
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
    (1, 2, 3, 4, 0, 6, 7, 8, 9, 5),
    (2, 3, 4, 0, 1, 7, 8, 9, 5, 6),
    (3, 4, 0, 1, 2, 8, 9, 5, 6, 7),
    (4, 0, 1, 2, 3, 9, 5, 6, 7, 8),
    (5, 9, 8, 7, 6, 0, 4, 3, 2, 1),
    (6, 5, 9, 8, 7, 1, 0, 4, 3, 2),
    (7, 6, 5, 9, 8, 2, 1, 0, 4, 3),
    (8, 7, 6, 5, 9, 3, 2, 1, 0, 4),
    (9, 8, 7, 6, 5, 4, 3, 2, 1, 0),
)

INVERSE: TupleType[int] = (0, 4, 3, 2, 1, 5, 6, 7, 8, 9)

PERMUTATION: TupleType[TupleType[int]] = (
    (0, 1, 2, 3, 4, 5, 6, 7, 8, 9),
    (1, 5, 7, 6, 2, 8, 3, 0, 9, 4),
    (5, 8, 0, 3, 7, 9, 6, 1, 4, 2),
    (8, 9, 1, 6, 0, 4, 3, 5, 2, 7),
    (9, 4, 5, 3, 1, 2, 6, 8, 7, 0),
    (4, 2, 8, 6, 5, 7, 3, 9, 0, 1),
    (2, 7, 9, 3, 8, 0, 6, 4, 1, 5),
    (7, 0, 4, 6, 9, 1, 3, 2, 5, 8),
)


[docs]def calculate(data: str) -> str: """Calculates a Verhoeff check digit. Args: data: A block of data without the check digit Returns: str: A string representing the missing check digit Examples: >>> from checkdigit import verhoeff >>> verhoeff.calculate('236') '3' >>> verhoeff.calculate('123456') '8' >>> verhoeff.calculate('1337') '5' """ checksum = 0 data = cleanse(data) # Start counting from 1 (hence enumerate(..., 1)) for count, value in enumerate(data[::-1], 1): checksum = DIHEDRAL_CAYLEY[checksum][PERMUTATION[count % 8][int(value)]] return str(INVERSE[checksum])
[docs]def validate(data: str) -> bool: """Validates a Verhoeff check digit. Args: data: A string of characters representing a full Verhoeff code. Returns: bool: A boolean representing whether the check digit validates the data or not. Examples: >>> from checkdigit import verhoeff >>> verhoeff.validate('585649') True >>> verhoeff.validate('13735') False """ return calculate(data[:-1]) == data[-1]
[docs]def missing(data: str) -> str: """Calculates a missing digit in a Verhoeff code. Args: data: A string of characters representing a full Verhoeff code with a question mark for a missing character Returns: str: The missing value that should’ve been where the question mark was Examples: >>> from checkdigit import verhoeff >>> verhoeff.missing("23?3") '6' >>> verhoeff.missing("999?") '8' >>> verhoeff.missing("123") 'Invalid' """ return missing_template(data, "verhoeff")