对增值税税号校验位算法不满

2024-05-15 17:44:12 发布

您现在位置:Python中文网/ 问答频道 /正文

我编写了一个函数来检查企业法人的增值税号码。这个函数可以工作,但是很难看(太长太复杂)。在

我是一个新的编程Python,希望改进函数,所以我需要一些反馈和帮助。在

增值税号码总是9位数字,第一位是字符,其余的是数字。在

字符必须在letras字符串中。在

最后一个数字是校验位。在

对于其他七个数字,算法如下:

  1. 偶数顺序的数字在小计中求和。在
  2. 奇数顺序的数字乘以2(每个数),如果每个结果大于等于10,则将单位加到十位数上,然后对四个结果进行小计。在
  3. 将添加步骤1和步骤2中获得的小计。在
  4. 得到单位,如果是0,那么校验位是0,在其他情况下是 扣除10英镑。结果是校验位。在

增值税编号为1858801

代码

def validarCodigoCIF(entrada):
    """
    :param: entrada: str
    :rtype: bool
    """
    letras = "ABCDEFGHIJKLMNPQRSVW"
    if len(entrada) != 9 or entrada[0] not in letras:
        return False
    numero = entrada[1:10]
    pares = int(numero[1]) + int(numero[3]) + int(numero[5])
    impares = 0
    for i in range(0, 8, 2):
        j = int(numero[i]) * 2
        if j < 10:
            impares += j
        else:
            impares += j - 9
    digito = str(pares+impares)[-1]
    if int(digito) == 0:
        checkCIF = 0
    else:
        checkCIF = 10 - int(digito)
    # print(checkCIF)
    if str(checkCIF) == entrada[-1]:
        return True
    else:
        return False

entradaCodigoCIF = input('Enter the VAT number: ')
print(validarCodigoCIF(entradaCodigoCIF))

Tags: 函数returnif数字else增值税int校验位
3条回答

这是一个简短的版本

def check(vat_num):
    if len(vat_num) != 9 or vat_num[0] not in "ABCDEFGHIJKLMNPQRSVW":
        return False # trivial checks first
    nums = list(map(int, vat_num[1:8])) # numbers to check
    nums[1::2] = ((i * 2) - (9 if i > 4 else 0) for i in nums[1::2]) # alter odds
    return int(vat_num[8]) == (sum(nums) % 10) # compare to check digit

请注意以下有趣的*功能:

  1. 使用[1::2]从iterable中获取所有其他项
  2. 使用map(int, ...)将interable中的所有项转换为整数;以及
  3. 使用% 10(模)可以很容易地得到数字的位数部分。在

*可能不有趣

首先要解决的问题是函数太长:

def calculate_pares(numero):
    return int(numero[1]) + int(numero[3]) + int(numero[5])

def calculate_impares(numero):
    result = 0
    for i in range(0, 8, 2):
        j = int(numero[i]) * 2
        if j < 10:
            result += j
        else:
            result += j - 9

    return result

def calculate_check_cif(entrada):
    numero = entrada[1:10]
    pares = calculate_pares(numero)
    impares = calculate_impares(numero)

    digito = str(pares+impares)[-1]
    if int(digito) == 0:
        return 0

    return 10 - int(digito)

def validarCodigoCIF(entrada):
    """
    :param: entrada: str
    :rtype: bool
    """
    letras = "ABCDEFGHIJKLMNPQRSVW"
    if len(entrada) != 9 or entrada[0] not in letras:
        return False

    checkCIF = calculate_check_cif(entrada)

    # print(checkCIF)
    return str(checkCIF) == entrada[-1]

这只是第一步,我想你明白了。当你有一些小的函数时,进一步的改进就更容易了。

另外,如果你用英语编写代码,这会更容易——也许人们会帮助你发现更多有意义的函数,而不仅仅是通过盲目的分区/猜测。

鉴于增值税号码使用Luhn校验和,我提出了一个我最近在an (unaccepted) answer上发布的关于信用卡号码的修改版本。

该函数不一定比您的短,但使用了另一种方法:对有效数字返回None,失败时返回简短的错误消息。它还可以确保首字母后面的数字是有效的,并允许使用空格和一些标点符号。

def invalid_cif_code(s):
    """ Returns None if s is a valid CIF code and a string 
        describing the error otherwise. The string may contain 
        spaces and punctuation, which is ignored.
    """

    # strip punctuation from string
    s = [x for x in s if x not in " \t.-"]

    if len(s) != 9:
        return "Invalid length"

    if s[0] not in "ABCDEFGHIJKLMNPQRSVW":
        return "Invalid initial letter"

    # convert numerical part to list of digits
    try:
        code = [int(x) for x in s[1:]]
    except ValueError:
        return "Invalid non-digit in number"

    # multiply and cast out nines for every other codeit   
    for i in range(0, 8, 2):
        code[i] *= 2
        if code[i] > 9:
            code[i] -= 9

    # calculate checksum            
    s = (9 * sum(code)) % 10

    if s != 0:
        return "Invalid checksum"

    return None

Typical Programmer对Luhn校验和有一个更优雅的解决方案(尽管它应用于信用卡号码并用Javascript编写),它对奇数使用数组。

相关问题 更多 >