我需要能够根据其校验位验证CUSIP号码。由于维基百科,我有这个过程的psudocode,但到目前为止我还无法用PHP复制它。
可以找到Psudocode here。
我的PHP:
<?php
/**
* function to return the check digit value of a cusip
* @param $cusip
* the cusip for processing.
* @return Int
* cusip check digit.
*/
function cusip_checksum($cusip){
$sum = 0;
$rebuiltcusip = '';
for($i = 1; $i <= 8; $i++){
$c = substr($cusip, ($i - 1), 1); //$i needs to be 0, so as we start at 1, take 1 off.
$rebuiltcusip .= $c;
switch(true){
case $c == '0': // ctype_digit(0) returns false, so checking for 0 here.
$v = $c;
watchdog("case 0: ", $v);
break;
case ctype_digit($c): //check if numeric
$v = $c;
watchdog("case ctype_digit: ", $v);
break;
case $c == '*':
$v = 36;
watchdog("case *: ", $v);
break;
case $c == '@':
$v = 37;
watchdog("case @: ", $v);
break;
case $c == '#':
$v = 38;
watchdog("case #: ", $v);
break;
case !ctype_digit($c): //check letter last as this check would pass with * @ or # so allow them to be checked first
$v = (ord($c) - 64) + 9; //set ordinal number, -64 as this returns ASKII value, then add 9.
watchdog("case not ctype_digit: ", $v);
break;
}
if(($i % 2) == 0){ //check if odd
$v = $v * 2;
watchdog("case odd: ", $v);
}
$sum = $sum + ($v / 10) + ($v % 10);
watchdog("sum end loop: ", $sum);
}
$ncd = (10 - ($sum % 10)) % 10;
$rebuiltcusip .= $ncd;
watchdog("rebuilt cusip: ", "Cusip: ".$cusip." Rebuilt: ".$rebuiltcusip);
return $ncd;
}
?>
看门狗只是我记录这个过程。
传入CUSIP:98986T108,其校验位值为8,实际返回值98986T104(校验位值为4)。
这样:
<?php
print cusip_checksum('98986T108');
?>
应该返回8,它返回4.
有人能发现原因吗?
答案 0 :(得分:2)
将分区包裹在floor()函数中,你就在那里:
$sum = $sum + floor($v / 10) + ($v % 10);
现在CUSIP中的Q值将为26.这将为$ sum添加2和6而不是添加2.6和6.
这是修正的最终功能。我通过路透社提取的17614 CUSIP进行了此操作,其中有11个没有匹配。这是关于我通常从路透社数据中看到的错误程度,所以我对这个例程充满信心。
/**
* function to return the check digit value of a cusip
* @param $cusip
* the cusip for processing.
* @return Int
* cusip check digit.
*/
function cusip_checksum($cusip){
$sum = 0;
$rebuiltcusip = '';
for($i = 1; $i <= 8; $i++){
$c = substr($cusip, ($i - 1), 1); //$i needs to be 0, so as we start at 1, take 1 off.
$rebuiltcusip .= $c;
switch(true){
case $c == '0': // ctype_digit(0) returns false, so checking for 0 here.
$v = $c;
watchdog("case 0: ", $v);
break;
case ctype_digit($c): //check if numeric
$v = $c;
watchdog("case ctype_digit: ", $v);
break;
case $c == '*':
$v = 36;
watchdog("case *: ", $v);
break;
case $c == '@':
$v = 37;
watchdog("case @: ", $v);
break;
case $c == '#':
$v = 38;
watchdog("case #: ", $v);
break;
case !ctype_digit($c): //check letter last as this check would pass with * @ or # so allow them to be checked first
$v = (ord($c) - 64) + 9; //set ordinal number, -64 as this returns ASKII value, then add 9.
watchdog("case not ctype_digit: ", $v);
break;
}
if(($i % 2) == 0){ //check if odd
$v = $v * 2;
watchdog("case odd: ", $v);
}
$sum = $sum + floor($v / 10) + ($v % 10);
watchdog("sum end loop: ", $sum);
}
$ncd = (10 - ($sum % 10)) % 10;
$rebuiltcusip .= $ncd;
watchdog("rebuilt cusip: ", "Cusip: ".$cusip." Rebuilt: ".$rebuiltcusip);
return $ncd;
}