如果我没错,ISIN号码的最后位置是一个验证位。 根据前11位数确定其值的数学函数是什么?
答案 0 :(得分:7)
http://en.wikipedia.org/wiki/International_Securities_Identification_Number
计算ISIN校验位的过程类似于CUSIP中使用的“Modulus 10 Double Add Double”技术。要计算校验位,首先通过将字母表中的序号位置加到9来将任何字母转换为数字,这样A = 10和M = 22.从最右边的数字开始,每隔一个数字乘以2。 (对于CUSIP校验位,这两个步骤相反。)将得到的数字字符串(大于9的数字变为两个单独的数字)相加。从以0结尾的最小数字减去这个总和大于或等于它:这给出了校验位,也就是模10的和10的十进制补码。也就是说,得到的总和,包括检查 - 数字,是10的倍数。
他们也有good example。
答案 1 :(得分:7)
基于其他人的例子,这里有一个C#实现,它将验证ISIN和CUSIP(以及其他一些Luhn变体)。
用法:
foreach (var isin in ValidIsins)
{
var calculatedChecksum = SecuritiesValidation.CalculateChecksum(isin.Substring(0, 11));
var actualChecksum = (isin.Last() - '0');
Assert.AreEqual(calculatedChecksum, actualChecksum);
}
foreach (var cusip in ValidCusips)
{
var calculatedChecksum = SecuritiesValidation.CalculateChecksum(cusip.Substring(0, 8), true, true);
var actualChecksum = (cusip.Last() - '0');
Assert.AreEqual(calculatedChecksum, actualChecksum);
}
实现:
public static class SecuritiesValidation
{
public static int CalculateChecksum(IEnumerable<char> codeWithoutChecksum, bool reverseLuhn = false, bool allowSymbols = false)
{
return reverseLuhn
? codeWithoutChecksum
.Select((c, i) => c.OrdinalPosition(allowSymbols).ConditionalMultiplyByTwo(i.IsOdd()).SumDigits())
.Sum()
.TensComplement()
: codeWithoutChecksum
.ToArray()
.ToDigits(allowSymbols)
.Select((d, i) => d.ConditionalMultiplyByTwo(i.IsEven()).SumDigits())
.Sum()
.TensComplement();
}
public static bool IsChecksumCorrect(string code, bool reverseLuhn = false, bool allowSymbols = false)
{
try
{
var checksum = code.Last().ToInt();
return checksum == CalculateChecksum(code.Take(code.Length - 1), reverseLuhn, allowSymbols);
}
catch
{
return false;
}
}
/* Be careful here. This method is probably inapropriate for anything other than its designed purpose of Luhn-algorithm based validation.
* Specifically:
* - numbers are assigned a value equal to the number ('0' == 0, '1' == 1).
* - letters are assigned a value indicating the number 9 plus the letters ordinal position in the English alphabet ('A' == 10, 'B' == 11).
* - if symbols are allowed (eg: for CUSIP validation), they are assigned values beginning from 36 ('*' == 36, '@' == 37).
*/
private static int OrdinalPosition(this char c, bool allowSymbols = false)
{
if (char.IsLower(c))
return char.ToUpper(c) - 'A' + 10;
if (char.IsUpper(c))
return c - 'A' + 10;
if (char.IsDigit(c))
return c.ToInt();
if (allowSymbols)
switch (c)
{
case '*':
return 36;
case '@':
return 37;
case '#':
return 38;
}
throw new ArgumentOutOfRangeException("Specified character is not a letter, digit or allowed symbol.");
}
private static bool IsEven(this int x)
{
return (x % 2 == 0);
}
private static bool IsOdd(this int x)
{
return !IsEven(x);
}
private static int ToInt(this char digit)
{
if (char.IsDigit(digit))
return digit - '0';
throw new ArgumentOutOfRangeException("Specified character is not a digit.");
}
private static IEnumerable<int> ToDigits(this char[] s, bool allowSymbols = false)
{
var digits = new List<int>();
for (var i = s.Length - 1; i >= 0; i--)
{
var ordinalPosition = s[i].OrdinalPosition(allowSymbols);
digits.Add(ordinalPosition % 10);
if (ordinalPosition > 9)
digits.Add(ordinalPosition / 10);
}
return digits;
}
private static int SumDigits(this int value)
{
//return value > 9 ? ((value / 10) + (value % 10)) : value;
return ((value / 10) + (value % 10));
}
private static int ConditionalMultiplyByTwo(this int value, bool condition)
{
return condition ? value * 2 : value;
}
private static int TensComplement(this int value)
{
return (10 - (value % 10)) % 10;
}
}
将校验和验证与正则表达式模式匹配结合使用可能是有意义的。这些是我使用的正则表达式:
ISIN:^(XS|AD|AE|AF|AG|AI|AL|AM|AO|AQ|AR|AS|AT|AU|AW|AX|AZ|BA|BB|BD|BE|BF|BG|BH|BI|BJ|BL|BM|BN|BO|BQ|BR|BS|BT|BV|BW|BY|BZ|CA|CC|CD|CF|CG|CH|CI|CK|CL|CM|CN|CO|CR|CU|CV|CW|CX|CY|CZ|DE|DJ|DK|DM|DO|DZ|EC|EE|EG|EH|ER|ES|ET|FI|FJ|FK|FM|FO|FR|GA|GB|GD|GE|GF|GG|GH|GI|GL|GM|GN|GP|GQ|GR|GS|GT|GU|GW|GY|HK|HM|HN|HR|HT|HU|ID|IE|IL|IM|IN|IO|IQ|IR|IS|IT|JE|JM|JO|JP|KE|KG|KH|KI|KM|KN|KP|KR|KW|KY|KZ|LA|LB|LC|LI|LK|LR|LS|LT|LU|LV|LY|MA|MC|MD|ME|MF|MG|MH|MK|ML|MM|MN|MO|MP|MQ|MR|MS|MT|MU|MV|MW|MX|MY|MZ|NA|NC|NE|NF|NG|NI|NL|NO|NP|NR|NU|NZ|OM|PA|PE|PF|PG|PH|PK|PL|PM|PN|PR|PS|PT|PW|PY|QA|RE|RO|RS|RU|RW|SA|SB|SC|SD|SE|SG|SH|SI|SJ|SK|SL|SM|SN|SO|SR|SS|ST|SV|SX|SY|SZ|TC|TD|TF|TG|TH|TJ|TK|TL|TM|TN|TO|TR|TT|TV|TW|TZ|UA|UG|UM|US|UY|UZ|VA|VC|VE|VG|VI|VN|VU|WF|WS|YE|YT|ZA|ZM|ZW)([0-9A-Z]{9})([0-9]{1})$
CUSIP:^[A-Z0-9]{8}[0-9]$
答案 2 :(得分:2)
根据维基百科发布的示例,方法是:
JavaScript中可能的实现是:
function getVerificationCode(isin)
{
if(isin.length != 12) return null;
var v = [];
for(var i = isin.length-2; i >= 0; i--)
{
var c = isin.charAt(i);
if(isNaN(c)) //Not a digit
{
var letterCode = isin.charCodeAt(i)-55; //Char ordinal + 9
v.push(letterCode % 10);
if(letterCode > 9)
v.push(Math.floor(letterCode/10));
}
else
v.push(Number(c));
}
var sum = 0;
var l = v.length;
for(var i = 0; i < l; i++)
if(i % 2 == 0)
{
var d = v[i]*2;
sum += Math.floor(d/10);
sum += d % 10;
}
else
sum += v[i];
return 10 - (sum % 10);
}
编辑:要包含@queso更新:
function getVerificationCode(isin) {
if (isin.length != 12) return false;
var v = [];
for (var i = isin.length - 2; i >= 0; i--) {
var c = isin.charAt(i);
if (isNaN(c)) { //not a digit
var letterCode = isin.charCodeAt(i) - 55; //Char ordinal + 9
v.push(letterCode % 10);
if (letterCode > 9) {
v.push(Math.floor(letterCode / 10));
}
} else {
v.push(Number(c));
}
}
var sum = 0;
var l = v.length;
for (var i = 0; i < l; i++) {
if (i % 2 == 0) {
var d = v[i] * 2;
sum += Math.floor(d / 10);
sum += d % 10;
} else {
sum += v[i];
}
}
return (10 - (sum % 10)) % 10
}
答案 3 :(得分:1)
由于 @pablo 和 @queso ,我与您分享了Matlab中的功能。
function isISIN = checkISINCode(Isin)
%
%
%
% see:
% - source:https://en.wikipedia.org/wiki/International_Securities_Identification_Number
% - source: https://stackoverflow.com/questions/16140753/how-to-validate-a-international-securities-identification-number-isin-number
%
%
isISIN = 0;
if length(Isin) ~= 12
return;
end
v = [];
for i = (length(Isin)-1):-1:1
c = Isin(i);
if isnan(str2double(Isin(i)))
% from ASCII
letterCode = double(upper(Isin(i))) - 64 + 9;
v = [mod(letterCode, 10), v];
if letterCode > 9
v = [floor(letterCode/10),v];
end
else
v = [int8(str2double(Isin(i))), v];
end
end
sum_ = 0;
l = length(v);
for i=1:l
if(mod(i-1,2) == 0)
d = v(i) * 2.;
sum_ = sum_ + floor( double(d) / 10.0);
sum_ = sum_ + mod(d, 10);
else
sum_ = sum_ + v(i);
end
end
checkValue = mod((10 - mod(sum_, 10)),10);
% Check Computed value with last digit
isISIN = int8(str2double(Isin(end))) == checkValue;
end
答案 4 :(得分:0)
我想在R中分享我的实现。它不需要任何特定的包。
mgsub是一个支持函数,它允许在一个命令中替换ISIN代码中的所有字符。它是从Replace multiple letters with accents with gsub
复制的 drawing layer
包含Grenade列出的国家/地区列表
该算法在iso3166alpha2$Code
函数中实现,在有效ISIN代码的情况下返回isIsin(x)
TRUE
答案 5 :(得分:0)
<?php
function cusipToIsin($CUSIP, $Country)
{
if (strlen($CUSIP) == 9) {
$string = charToCusipBinary($Country) . charToCusipBinary($CUSIP); //Convert any letters to numbers
$arrayString = str_split($string);
//check wether string length is even or odd
if (strlen($string) % 2 != 0) {
$num = 0;
foreach ($arrayString as $key => $value) {
//Collect odd and even characters
if ($key % 2 != 0) {
$values = $value;
} else {
$values = $value * 2; //The key is in odd position, so Multiply by 2
}
$sumValue = array_sum(str_split($values)); //Add up the individual digits
$num += $sumValue;
}
$isinCheckDigit = (10 - ($num % 10)) % 10;
$result1 = strtoupper($Country . $CUSIP . $isinCheckDigit);
} else {
$num = 0;
foreach ($arrayString as $key => $value) {
//Collect odd and even characters
if ($key % 2 != 0) {
$values = $value * 2; //The key is in even position, so Multiply by 2
} else {
$values = $value;
}
$sumValue = array_sum(str_split($values)); //Add up the individual digits
$num += $sumValue;
}
$isinCheckDigit = (10 - ($num % 10)) % 10;
$result1 = strtoupper($Country . $CUSIP . $isinCheckDigit);
}
$Validate = isinValidate($result1);
if ($Validate == true) {
$result = $result1;
} else {
$result = 'Please check the CUSIP';
}
} else {
$result = 'Please check the CUSIP';
}
return $result;
}
function charToCusipBinary($string)
{
return strtr(strtoupper($string), ['A' => '10', 'B' => '11', 'C' => '12', 'D' => '13', 'E' => '14', 'F' => '15', 'G' => '16', 'H' => '17', 'I' => '18', 'J' => '19', 'K' => '20', 'L' => '21', 'M' => '22', 'N' => '23', 'O' => '24', 'P' => '25', 'Q' => '26', 'R' => '27', 'S' => '28', 'T' => '29', 'U' => '30', 'V' => '31', 'W' => '32', 'X' => '33', 'Y' => '34', 'Z' => '35']);
}
function isinValidate($isin)
{
if (!preg_match('/^[A-Z]{2}[A-Z0-9]{9}[0-9]$/i', $isin)) {
return false;
}
$base10 = '';
for ($i = 0; $i <= 11; $i++) {
$base10 .= base_convert($isin{$i}, 36, 10);
}
$checksum = 0;
$len = strlen($base10) - 1;
$parity = $len % 2;
for ($i = $len; $i >= 0; $i--) {
$weighted = $base10{$i} << (($i - $parity) & 1);
$checksum += $weighted % 10 + (int) ($weighted / 10);
}
return !(bool) ($checksum % 10);
}
echo cusipToIsin('78012KD61', 'US'); //ISIN: US78012KD617
?>
答案 6 :(得分:0)
这是Swift中的一种方法。
它首先检查要求的2个字母+ 10个带正则表达式的字母数字字符
func validateISIN(_ isin : String) -> Bool {
guard isin.range(of: "^[A-Z]{2}[A-Z0-9]{10}$", options: .regularExpression) != nil,
let checksum = Int(isin.suffix(1)) else { return false }
let digits = isin.dropLast().map{Int(String($0), radix: 36)!}.map(String.init).joined()
var sum = 0
var evenFlag = true
digits.reversed().forEach { character in
var integer = Int(String(character))!
if evenFlag { integer *= 2 }
sum += integer / 10
sum += integer % 10
evenFlag.toggle()
}
return (10 - (sum % 10)) % 10 == checksum
}
答案 7 :(得分:0)
用于验证校验和的 kotlin 版本:
fun check(isin: String): Boolean {
val isinInts = isin.map { it.toString().toInt(36) }
.joinToString("").map { Character.getNumericValue(it) }
val multipliers = isinInts.indices.map { it % 2 + 1 }.reversed()
val sum = multipliers.indices.sumOf { index: Int ->
(isinInts[index] * multipliers[index]).let { it / 10 + it % 10 }
}
return (10 - (sum % 10)) % 10 == 0
}