Beispiel #1
0
def validate(data: str) -> bool:
    """Validates a luhn check digit.

    Args:
        data: A string of characters representing a full luhn code

    Returns:
        bool: A boolean representing whether the check digit validates the data or not

    Examples:
        >>> from checkdigit import luhn
        >>> luhn.validate("541756116585277")
        True
        >>> luhn.validate("79927398713")
        True
        >>> luhn.validate("49927398717")
        False
        >>> luhn.validate("1234567812345678")
        False

    """
    data = cleanse(data)
    return (
        calculate(data[:-1]) == data[-1]
    )  # Determines if calculated Check Digit of the data is the last digit given
Beispiel #2
0
def calculate(data: str, even: bool = True) -> str:
    """Adds a parity bit onto the end of a block of data.

    Args:
        data: A string containing binary digits
        even: Whether to use even or odd parity (defaults to even)

    Returns:
        str: The parity bit of the data

    Examples:
        >>> from checkdigit import parity
        >>> # Even parity
        >>> parity.calculate("0110")
        '0'
        >>> parity.calculate("01101")
        '1'

        >>> # Odd parity
        >>> parity.calculate("01101", False)
        '0'
        >>> parity.calculate("0", False)
        '1'

    """
    data = cleanse(data)
    if (even and not data.count("1") % 2) or (not even
                                              and data.count("1") % 2):
        return "0"
    return "1"
Beispiel #3
0
def validate(data: str, even: bool = True) -> bool:
    """Validates whether the check digit matches a block of data.

    Args:
        data: A string containing binary digits
        even: Whether to use even or odd parity (defaults to even)

    Returns:
        bool: A boolean representing whether the data is valid or not

    Examples:
        >>> from checkdigit import parity
        >>> # Even parity
        >>> parity.validate("01100")
        True
        >>> parity.validate("01101")
        False

        >>> # Odd parity
        >>> parity.validate("01101", False)
        True
        >>> parity.validate("01100", False)
        False
    """
    data = cleanse(data)
    return calculate(data[:-1], even) == data[-1]
Beispiel #4
0
def calculate(data: str, polynomial: str, pad: str = "0") -> str:
    """Adds a parity part onto the end of a block of data.

    Args:
        data: A string containing binary digits of any length
        polynomial: A string of binary digits representing the polynomial being used
        pad: "1" or "0" or nothing to be used to pad the data (defaults to 0)

    Returns:
        str: Check Value that should be appended to the stream

    Examples:
        >>> from checkdigit import crc
        >>> crc.calculate("1010", "1011")
        '011'
        >>> crc.calculate("100110010100111101111101", "11010111101")
        '0010001100'
    """
    data = cleanse(data)
    data += pad * (len(polynomial) - 1)
    bitarray = list(data)
    while len(bitarray) != len(polynomial) - 1:
        for position, bit in enumerate(polynomial):
            # XOR calculation
            bitarray[position] = "0" if bit == bitarray[position] else "1"
        while bitarray[0] == "0" and len(bitarray) >= len(polynomial):
            bitarray.pop(0)

    return "".join(bitarray)
Beispiel #5
0
def missing(data: str) -> str:
    """Calculates a missing digit in an ISBN Code represented by a question mark.

    Args:
        data: A string of characters representing a full ISBN code
            with a question mark representing a missing character

    Returns:
        str: The missing value that should've been where the question mark was

    """
    data = cleanse(data)
    data_length = len(data)  # ISBN-10 or 13
    # We already have an efficient method for the checkdigit
    if data[-1] == "?":
        # Remove question mark check digit
        return calculate10(data[:-1]) if data_length == 10 else calculate13(data[:-1])

    # We've dealt with the check digit, so X can't be an option
    # Brute force all the possible numbers (0-9 inclusive)
    for option in (data.replace("?", str(i)) for i in range(10)):
        # Validate the new option
        if (
            data_length == 10
            and validate10(option)
            or data_length == 13
            and validate13(option)
        ):
            # Replace question mark with new value
            return option[data.index("?")]
    return "Invalid"
Beispiel #6
0
def calculate(data: str) -> str:
    """Calculates the luhn 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 luhn
        >>> luhn.calculate("53251309870224")
        '3'
        >>> luhn.calculate("950123440000")
        '8'

    """
    data = cleanse(data)
    # Double every other digit, starting from the final digit backwards
    # i.e. double 0th digit, 2nd, 4th, ...
    double_digits = (int(element) if index % 2 else int(element) * 2
                     for index, element in enumerate(data[::-1]))
    # For digits with more than one digit, sum the digits together
    # The maximum is 9*2 = 18. This divmod method will work <100
    sum_digits = sum(sum(divmod(i, 10)) for i in double_digits)
    # Mod 10 returns 0-9 (not 10 or 11)
    # Hence convert method not required (faster to use str)
    return str((sum_digits * 9) % 10)
Beispiel #7
0
def validate(data: str, even: bool = True) -> bool:
    """Validates whether the check digit matches a block of data.

    Args:
        data: A string containing binary digits
        even: Whether to use even or odd parity (defaults to even)

    Returns:
        bool: A boolean representing whether the data is valid or not
    """
    data = cleanse(data)
    return calculate(data[:-1], even) == data[-1]
Beispiel #8
0
def validate13(data: str) -> bool:
    """Validates ISBN-13.

    Args:
        data: A string of characters representing a full ISBN-13 code

    Returns:
        bool: A boolean representing whether the check digit validates the data

    """
    data = cleanse(data)
    return calculate13(data[:-1]) == data[-1]
Beispiel #9
0
def calculate(data: str, even: bool = True) -> str:
    """Adds a parity bit onto the end of a block of data.

    Args:
        data: A string containing binary digits
        even: Whether to use even or odd parity (defaults to even)

    Returns:
        str: The parity bit of the data
    """
    data = cleanse(data)
    if (even and not data.count("1") % 2) or (not even and data.count("1") % 2):
        return "0"
    return "1"
Beispiel #10
0
def calculate(data: str, even: bool = True) -> str:
    """Adds a parity bit onto the end of a block of data.

    Args:
        data: A string containing binary digits
        even: Whether to use even parity (otherwise uses odd parity)

    Returns:
        str: The original data with the parity bit added to the end
    """
    data = cleanse(data)
    if (even and not data.count("1") % 2) or (not even
                                              and data.count("1") % 2):
        return data + "0"
    return data + "1"
Beispiel #11
0
def calculate10(data: str) -> str:
    """Calculates ISBN-10 Check Digit.

    Args:
        data: A string of 9 characters

    Returns:
        str: The check digit that was missing
    """
    data = cleanse(data)
    # Multiply first digit by 10, second by 9, ... and take the sum
    total_sum = sum(
        int(digit) * weight for digit, weight in zip(data, range(10, 0, -1))
    )
    return convert(11 - (total_sum % 11))
Beispiel #12
0
def validate(data: str) -> bool:
    """Validates GS1.

    This method works for all fixed length numeric GS1 data structures
    (including GDTI, GLN, GRAI, etc.) that require a check digit.

    Args:
        data: A string of characters representing a full GS1 code

    Returns:
        bool: A boolean representing whether the
            check digit validates the data or not

    """
    data = cleanse(data)
    return calculate(data[:-1]) == data[-1]
Beispiel #13
0
def calculate10(data: str) -> str:
    """Calculates ISBN-10 Check Digit.

    Args:
        data: A string of 9 characters

    Returns:
        str: The check digit that was missing
    """
    data = cleanse(data)
    total_sum = 0
    multiply_counter = 10
    for item in data:
        total_sum += int(item) * multiply_counter
        multiply_counter -= 1  # Multiplies first digit by 10, second by 9...
    check_digit = 11 - (total_sum % 11)
    return convert(check_digit)
Beispiel #14
0
def calculate13(data: str, barcode: str = "isbn") -> str:
    """Calculates ISBN-13 Check Digit.

    Args:
        data: A string of 12 characters
        barcode: The type of code (either isbn or upc)

    Returns:
        str: The check digit that was missing
    """
    data = cleanse(data)
    # ISBN weights is 1 for odd positions and 3 for even
    # The opposite is true for upc
    weights = (1, 3) * 6 if barcode == "isbn" else (3, 1) * 6
    # Multiply each digit by its weight
    total_sum = sum(int(digit) * weight for digit, weight in zip(data, weights))
    # Return final check digit and type of barcode
    return convert(10 - (total_sum % 10), barcode)
Beispiel #15
0
def validate(data: str, polynomial: str) -> bool:
    """Validates whether the check digit matches a block of data.

    Args:
        data: A string containing binary digits including the check digit
        polynomial: Polynomial to use

    Returns:
        bool: A boolean representing whether the data is valid or not

    Examples:
        >>> from checkdigit import crc
        >>> crc.validate("1010101", "101")
        True
        >>> crc.validate("1000101", "101")
        False
    """
    data = cleanse(data)
    # the principle of CRCs is that when done again but with the check digit
    # appended if the data is fine it should all be 0s
    return "0" * (len(polynomial) - 1) == calculate(data, polynomial, "")
Beispiel #16
0
def missing(data: str) -> str:
    """Calculates a missing digit in a GS1 Code.

    This method works for all fixed length numeric GS1 data structures
    (including GDTI, GLN, GRAI, etc.) that require a check digit.

    Args:
        data: A string of characters representing a full ISBN code
            with a question mark representing a missing character

    Returns:
        str: The missing value that should've been where the question mark was

    """
    data = cleanse(data)
    for poss_digit in range(10):  # Brute Force the 10 options
        option = convert(poss_digit)
        # tests it with the generated number
        # If this fails, the next number is tried
        if validate(data.replace("?", option)):
            return option
    return "Invalid"
Beispiel #17
0
def missing(data: str) -> str:
    """Calculates a missing digit in an ISBN Code.

    Args:
        data: A string of characters representing a full ISBN code
            with a question mark representing a missing character

    Returns:
        str: The missing value that should've been where the question mark was

    """
    data = cleanse(data)
    for poss_digit in range(11):  # Brute Force the 11 options
        option = convert(poss_digit)
        # Depending on the size of the data, the relevant validating function
        # tests it with the generated number
        # If this fails, the next number is tried
        if (len(data) == 10 and validate10(data.replace("?", option))) or (
            len(data) == 13 and validate13(data.replace("?", option))
        ):
            return option
    return "Invalid"
Beispiel #18
0
def calculate13(data: str, barcode: str = "isbn") -> str:
    """Calculates ISBN-13 Check Digit.

    Args:
        data: A string of 12 characters
        barcode: The type of code (either isbn or upc)

    Returns:
        str: The check digit that was missing
    """
    data = cleanse(data)
    mod_number = 0 if barcode == "isbn" else 1
    total_sum = 0
    position_counter = 1  # 1 based indexing for data
    for item in data:
        digit = int(item)
        if position_counter % 2 == mod_number:
            total_sum += digit * 3  # Multiplies by 3 if position is even
        else:
            total_sum += digit
        position_counter += 1
    final_value = 10 - (total_sum % 10)
    return convert(final_value, barcode)
Beispiel #19
0
def calculate(data: str) -> str:
    """Calculates GS1 Check Digit.

    This method works for all fixed length numeric GS1 data structures
    (including GDTI, GLN, GRAI, etc.) that require a check digit.

    Args:
        data: A string of characters

    Returns:
        str: The check digit that was missing
    """
    data = cleanse(data)
    data = data[::-1]  # Reverse the barcode, as last digit is always multiplied by 3
    total_sum = 0
    for index, value in enumerate(data):
        if index % 2 == 0:
            total_sum += int(value) * 3
        else:
            total_sum += int(value)
    next_multiple_of_ten = int(math.ceil(total_sum / 10.0)) * 10
    check_digit = next_multiple_of_ten - total_sum
    return convert(check_digit, "gs1")
Beispiel #20
0
def calculate(data: str) -> str:
    """Calculates ISBN Check Digits.

    Args:
        data: A string of characters representing an ISBN code without the check digit

    Returns:
        str: The check digit that was missing

    Examples:
        >>> from checkdigit import isbn
        >>> # ISBN-10
        >>> isbn.calculate("043942089")
        'X'
        >>> # ISBN-13
        >>> isbn.calculate("978-1-86197-876")
        '9'
    """
    data = cleanse(data)

    if len(data) == 9:
        # ISBN 10 (without the check digit)
        # Multiply first digit by 10, second by 9, ... and take the sum
        total_sum = sum(
            int(digit) * weight for digit, weight in zip(data, range(10, 0, -1))
        )
        return convert(11 - (total_sum % 11))
    # elif not required since return above (and makes pylint happy)
    if len(data) == 12:
        # ISBN weights is 1 for odd positions and 3 for even
        # Since there are 12 digits, multiply weights by 6
        weights = (1, 3) * 6
        # Multiply each digit by its weight
        total_sum = sum(int(digit) * weight for digit, weight in zip(data, weights))
        # Return final check digit and type of barcode
        return convert(10 - (total_sum % 10))
    return "Invalid"