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 """ data = cleanse(data) position_counter = 1 # 1-based indexing total_sum = 0 for item in data[::-1]: # Reverses String digit = int(item) if position_counter % 2: # If position number is odd with reversed string add_value = digit * 2 if add_value > 9: for number in str( add_value): # Adds individual digits together total_sum += int(number) else: total_sum += add_value else: total_sum += digit position_counter += 1 return convert(10 - (total_sum % 10), "luhn")
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]
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 """ data = cleanse(data) return ( calculate(data[:-1]) == data[-1] ) # Determines if calculated Check Digit of the data is the last digit given
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"
def missing(data: str) -> str: """Calculates a missing digit in a luhn code Args: data: A string of characters representing a full luhn code with a question mark for 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 if validate(data.replace("?", str(poss_digit))): return str(poss_digit) return "Invalid"
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)
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"
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)