在 C# 中验证增值税号
本文关键字:增值税 验证 | 更新日期: 2023-09-27 18:28:28
增值税号码不是随机或顺序生成的,而是基于可以检查该号码是否有效的公式。如果增值税号无效,企业无法重新申报增值税。
要手动验证英国增值税税号,您可以执行以下练习:
不包括前 2 个字母,垂直列出数字,并将每个数字乘以以 8 开头并以 2 结尾的值。然后将您拥有的所有总和相加,并从总和中扣除 97,直到答案是否定的。负数应等于增值税号的最后 2 位数字。
例如,BLABLA
的增值税号是 GB,815382334计算结果是:
8 x 8 = 64
1 x 7 = 7
5 x 6 = 30
3 x 5 = 15
8 x 4 = 32
2 x 3 = 6
3 x 2 = 6
上述计算的总和为64 + 7 + 30 + 15 + 32 + 6 + 6 = 160
从中扣除 97,直到结果为负数,结果为 160 – 97 - 97= -34
与最后两位数字相同:因此增值税号有效。
我想编写一个 C# 应用程序,该应用程序将英国增值税号作为输入,使用上述公式计算校验和,并指示该号码是有效还是无效。
对我来说,这是算法的练习。我在网上找到了增值税检查器,但我不明白它们是如何工作的,所以我希望有人能对上述问题给出一些简单的答案,并给出很好的解释?
更新:
public static bool isValidVATNumber(string theVATNumber)
{
string startChar = "^";
string endChar = "$";
bool rtn = false;
int i = 8;
string valString;
int sum = 0;
// Check that the string matches the requirements
rtn = Regex.IsMatch(theVATNumber, (startChar + ("(([1-9]d{8})|([1-9]d{11}))" + endChar)), RegexOptions.Multiline);
if (rtn)
{
// Perform the validation
valString = theVATNumber;
if (Regex.IsMatch(valString, (startChar + "[A-Z]{2}"), RegexOptions.Multiline))
{
valString = valString.Substring(2);
}
while ((i >= 2))
{
sum = (sum
+ (i * int.Parse(valString.Substring(0, 1))));
valString = valString.Substring(1);
i--;
}
while ((sum > 0))
{
sum -= 97;
}
rtn = ((sum * -1)
== int.Parse(valString));
}
return rtn;
}
请注意,上述方法不起作用,对我来说更难理解,我从我自己的方法开始,我发现它更容易使用,但尚未完成(请注意这很尴尬(
List<int> integerList = new List<int>();
int b = 8;
for (int a = 0; a < textBox1.Text.Length; a++)
{
integerList.Add(int.Parse(textBox1.Text[a].ToString()));
}
foreach (int item in integerList)
{
listBox1.Items.Add(item * b);
--b;
}
我仍然需要获取列表的总和并进行其余的计算,并希望挑选一些人的大脑来寻找其他方法(更简单的方法(。
更新我自己的方法,并在下面感谢Pax:
List<int> integerList = new List<int>();
List<int> sumList = new List<int>();
int b = 8; // Will be 8 for the first multiplication.
for (int a = 0; a <= 6; a++)
{
integerList.Add(int.Parse(textBox1.Text[a].ToString()));
}
foreach (int item in integerList) // Loop once per input digit.
{
//listBox1.Items.Add(item * b);
sumList.Add(item * b);
--b;
}
listBox1.DataSource = sumList;
int sum = sumList.Sum();
while (sum > 0)
{
sum = sum - 97;
}
int myInt = System.Math.Abs(sum);
label1.Text = Convert.ToString(myInt);
好的,让我们一点一点地看一下。假设您有代码815382334
- 您已经删除了前面的不相关字符。
第一步是循环遍历字符并保持数值乘以索引的运行总计(,在伪代码中:
sum = 0
for pos = 0 to 6 inclusive:
sum = sum + num_at(pos) * (8 - pos)
对于上述循环的每次迭代,您从字符串中提取正确的数字并将其乘以其索引,该索引从 8
开始,向下到 2
。然后将其添加到sum
变量中。请记住,num_at()
方法需要为您提供一个从 0 到 9(包括 0 和 9(的整数,而不是字符代码本身,后者很可能是0x30
到 0x39
的。
我经常发现初学者更容易坐下来运行程序,使用他们的 noggin 作为 CPU 和一些用于存储的纸张,例如:
pos num_at(pos) 8-pos add sum
--- ----------- ----- --- ---
0
0 8 8 64 64
1 1 7 7 71
2 5 6 30 101
3 3 5 15 116
4 8 4 32 148
5 2 3 6 154
6 3 2 6 160
第二步,按照规范减去 97,直到变为负数:
while sum > 0:
sum = sum - 97
(尽管您可能可以更有效地使用模运算符(。再一次,在你的脑海中运行它:
sum
---
160
63
34-
然后,作为第三步也是最后一步,将最后两位数字(作为完整的两位数字(相加以确保得到零:
sum = sum + num_at(7) * 10 + num_at(8)
return (sum == 0);
由于位置 7 和 8 处的数字分别是3
和4
,num_at(7) * 10 + num_at(8)
会给你 34
,这是您要加回负调整总和的内容。
模数版本允许如下:
sum = 0
for pos = 0 to 6 inclusive:
sum = sum + num_at(pos) * (8 - pos)
return ((sum % 97) + num_at(7) * 10 + num_at(8) == 97);
这是有效的sum % 97
实际上与给你一个负数但没有最终减法 97 的循环相同。因此,当您加回最后两位数字时,您将获得 97 而不是 0(对于有效的增值税号(。
例如,160 % 97
给你63
,63 + 34
给你97
。
现在,根据您添加的代码片段,您可能需要处理两种类型的增值税号,即 9 位数字和 12 位数字的增值税号。发布的代码片段可能比所有正则表达式检查和子字符串所需的要复杂一些,其中长度检查、简单的字符串索引和字符检查就足够了。
我在 C# 中的方法如下...我已经用一些值快速测试了它,但请确保在使用它之前正确测试它。我试图选择显示意图清晰而不是性能的代码,以便可以优化一些位,但我认为除非您进行数百万次验证,否则不值得付出努力。
public static class VAT
{
/// <summary>
/// Validates a GB VAT number
/// </summary>
public static bool ValidateGBVatNumber(string vatNumber)
{
vatNumber = vatNumber.Replace(" ", "").ToUpperInvariant();
if (vatNumber.Length == 11)
{
if (vatNumber[0] == 'G' && vatNumber[1] == 'B')
{
vatNumber = vatNumber.Substring(2);
}
else
{
// First digits are not GB
return false;
}
}
if (vatNumber.Length != 9)
{
// Wrong length even after removing spaces and getting rid of the first two characters
return false;
}
// Provided number has 9 digits, which is correct. Proceed to calculate checksum
int runningTotal = 0;
int[] multipliersByIndex = new int[] {8, 7, 6, 5, 4, 3, 2};
for (int i = 0; i < 7; i++)
{
int currentDigitValue;
if (!int.TryParse(vatNumber[i].ToString(), out currentDigitValue))
{
// Could not parse a digit into an int => wrong character supplied
return false;
}
runningTotal += currentDigitValue * multipliersByIndex[i];
}
// Subtract 97 until negative - this could perhaps be better done with the modulus operator
// but this way might be more 'obvious'
while (runningTotal >= 0)
{
runningTotal -= 97;
}
// Convert to a string that will have two digits even if the number only has one
string checkSum = (runningTotal * -1).ToString("00");
return (checkSum[0] == vatNumber[7] && checkSum[1] == vatNumber[8]);
}
}
用法示例:
isValid = VAT.ValidateGBVatNumber("GB 815382334"); // True
isValid = VAT.ValidateGBVatNumber("GB815382334"); // True
isValid = VAT.ValidateGBVatNumber("815382334"); // True
isValid = VAT.ValidateGBVatNumber("GB 815382335"); // False
isValid = VAT.ValidateGBVatNumber("GB 81538233424242"); // False
isValid = VAT.ValidateGBVatNumber("YHUWOCNYEX"); // False