提问人:Janne 提问时间:10/24/2023 最后编辑:mickmackusaJanne 更新时间:10/26/2023 访问量:103
根据公式计算参考编号
Calculating reference number from formula
问:
如何在有效的PHP代码中转换这个“参考编号”公式?
如果有人能帮助我,我会把 fromula 放在这里!
就我而言:
客户编号默认为 1 每次/always。
发票编号由用户确定
验证号的计算公式为:
参考号的验证位是通过从右到左乘以权重为 7、3、1、7、3、1...并总结这些产品。然后从下一个完整的十中减去乘积的总和,得到验证数字。如果结果为 10,则改用数字 0。
参考编号计算示例:客户编号:1
发票编号:25(发票编号至少有 4 位数字,如果插入的发票编号小于 4 位数字,如 25,则需要添加零 (0) 才能等于 4 位数字。所有零都将添加到左侧站点。在此示例中,25 -> 0025。如果客户编号是 4 位数字,例如 1234,则就是该数字)
参考编号以: 10025
5 -> 5 * 7 = 35
2 -> 2 * 3 = 6
0 -> 0 * 1 = 0
0 -> 0 * 7 = 0
1 -> 1 * 3 = 3
乘积之和 (35 + 6 + 0 + 0 + 3) 为 44。下一个完整的十是 50。因此,验证位数为 50 - 44 = 6。
最终参考编号为:100256
这是我尝试过的:
<?php
$customerNumber = 1;
$invoiceNumber = 765;
$baseReferenceNumber = "{$customerNumber} 0 {$invoiceNumber}";
$entries = str_split(str_replace(' ', '', $baseReferenceNumber));
$sum = 0;
foreach ($entries as $entry) {
$sum += $entry * (($sum % 2) + 1);
}
$totalSum = $sum;
$nextFullTen = ceil($totalSum / 10) * 10;
$checkNumber = $nextFullTen - $totalSum;
$finalReferenceNumber = "{$baseReferenceNumber} {$checkNumber}";
echo "Final Reference Number: {$finalReferenceNumber}";
?>
但这给了我107653结果,而真正的答案是 1 07657
答:
声明常量值和用户输入变量/常量后,基本上有 5 个子任务。
- 使用填充零组合引用基本字符串(填充不是动态的)。
- 从最后一个到第一个迭代数字字符(您的迭代是从前面开始的)。
- 执行加权算术并对结果求和(请参阅我的模运算符数学)。
- 将总数向上舍入到最接近的 10,然后从该数字中减去总数以生成验证数字。
- 将该结果追加到参考库。
如果您喜欢经典的循环结构,循环将允许您从字符串的后面迭代字符。(演示for()
)
define('WEIGHTS', [7, 3, 1]);
define('WEIGHTS_COUNT', count(WEIGHTS));
$customerNumber = 1;
$invoiceNumber = 25;
$refBase = sprintf('%d%04d', $customerNumber, $invoiceNumber);
$weightedSum = 0;
for ($x = 0, $i = strlen($refBase) - 1; $i >=0; --$i, ++$x) {
$weightedSum += $refBase[$i] * WEIGHTS[$x % WEIGHTS_COUNT];
}
echo $refBase . (ceil($weightedSum / 10) * 10 - $weightedSum);
如果您更喜欢函数式风格语法,则可以用作循环。声明只允许将计数器传递给后续迭代(否则它将被“遗忘”)。(演示array_reduce()
static
$i
)
$refBase = sprintf('%d%04d', $customerNumber, $invoiceNumber);
$weightedSum = array_reduce(
array_reverse(str_split($refBase)),
function($result, $v) {
static $i;
$i ??= 0;
return $result + ($v * WEIGHTS[$i++ % WEIGHTS_COUNT]);
},
0
);
echo $refBase . (ceil($weightedSum / 10) * 10 - $weightedSum);
如果你希望有一个更丑陋的版本,就在这里。你可以通过内联声明将所有子任务分解成一个单行,然后连接一个 IIFE 的结果,这将消耗 重新调整的验证位。把你的barfbag放在手边。(演示$refBase
array_reduce()
)
echo ($refBase = sprintf('%d%04d', $customerNumber, $invoiceNumber))
. $verificationDigit = (
fn($weightedSum) => (ceil($weightedSum / 10) * 10 - $weightedSum)
)(array_reduce(
str_split(strrev($refBase)),
function($result, $v) {
static $i;
$i ??= 0;
return $result + ($v * WEIGHTS[$i++ % WEIGHTS_COUNT]);
},
0
)
);
这是解决方案之一,我试图让它变得非常简单易懂。
$basis = [7, 3, 1, 7, 3, 1];
$customer_number = 1;
$invoice_number = 25;
$padded_invoice_number = '';
$padded_invoice_number = str_pad($invoice_number,4,"0", STR_PAD_LEFT);
$reference_number_base = ( $customer_number . $padded_invoice_number);
$reference_number_base_reversed = strrev($reference_number_base);
$sum_of_the_products = 0;
for ($i=0; $i < strlen($reference_number_base_reversed); $i++) {
$sum_of_the_products += (int) $reference_number_base_reversed[$i] * $basis[$i];
}
$next_full_ten = ceil($sum_of_the_products/10) * 10;
$verification_digit = $next_full_ten - $sum_of_the_products;
$final_reference_number = ($reference_number_base . $verification_digit);
评论
$basis
评论