2013-04-22 123 views

回答

7

http://en.wikipedia.org/wiki/International_Securities_Identification_Number

用於計算ISIN校驗位的過程類似於在CUSIPs所使用的「模量10雙人添加雙」技術。要計算校驗位,首先將任意字母轉換爲數字,方法是將它們在字母表中的順序位置添加到9,使得A = 10和M = 22。從最右側的數字開始,每隔一位數字乘以2。 (對於CUSIP檢查數字,這兩個步驟是相反的。)結果字符串數字(大於9的數字成爲兩個單獨的數字)相加。從以0結尾的最小數字中減去大於或等於它的總和:這給出了校驗位,它也被稱爲模10的和的十進制補數。也就是說,結果總和(包括校驗和)數字,是10的倍數。

他們也有good example

+0

這樣的描述情況下返回TRUE實施有一些錯誤: 「...每隔一位數字乘以二」。 正如我可以在其他參考中找到,並檢查示例:不是每個其他數字,但替代數字乘以兩。 – 2013-04-22 07:18:11

+0

@PabloFranciscoPérezHidalgo:把「其他數字」解釋爲「替代數字」是完全合理的。您不清楚您認爲維基百科條目中的錯誤是什麼。 – 2013-04-22 08:47:51

2

基於發表在維基百科的例子中,該方法是:

  1. 通過其序替換每個字母(A = 1,B = 2等),加上9 - >enter image description here
  2. 對於每個從最右邊的位置(enter image description here)開始,在一個偶數位置處將其替換爲其雙倍數字(兩個矢量條目中的兩位數字) - >enter image description here;
  3. 驗證碼:

enter image description here

在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 
} 
+1

對於上面的代碼,ISIN XS0977502110無法在這裏看到:http://en.wikipedia.org/wiki/International_Securities_Identification_Number#External_links我能夠在這裏更新您的代碼http://jsfiddle.net/markbenda/nh2w1Lbh/16/。謝謝你做了很難的部分。 – Queso 2015-02-03 17:45:00

+0

@Queso我編輯了我的答案,以包含您的代碼建議。感謝您的改進! – 2015-03-20 18:38:53

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]$

0

我想分享我實施R.它不需要任何特定的包。

mgsub是一個支持函數,它允許在一個命令中替換ISIN代碼中的所有字符。它是由Replace multiple letters with accents with gsub

iso3166alpha2$Code複製包含Grenade已經上市的國家名單

該算法在isIsin(x)功能,在有效的ISIN代碼

mgsub <- function(pattern, replacement, x, ...) { 
    if (length(pattern)!=length(replacement)) { 
    stop("pattern and replacement do not have the same length.") 
    } 
    result <- x 
    for (i in 1:length(pattern)) { 
    result <- gsub(pattern[i], replacement[i], result, ...) 
    } 
    result 
} 

isIsin <- function (identifier) { 

    correctPrefix <- substr(identifier, 1, 2) %in% c(iso3166alpha2$Code, "XS") 

    correctLength <- nchar(identifier) == 12 

    correctCharset <- !grepl('[[:punct:]]', identifier) 

    if(!correctPrefix | !correctLength | !correctCharset) { 
    return(FALSE) 
    } 

    # replace all character with its equivalent number 
    identifierOnlyNumbers <- mgsub(LETTERS, seq(10, 35), substr(identifier, 1, 11)) 

    # split the identifier in single digits and reverse its order 
    characterVector <- rev(unlist(strsplit(identifierOnlyNumbers, ""))) 

    # Double every second digit of the group of digits with the rightmost character 
    characterVector[seq(1, nchar(identifierOnlyNumbers), 2)] <- 
    as.character(as.numeric(characterVector[seq(1, nchar(identifierOnlyNumbers), 2)]) * 2) 

    # Subtract 9 if > 9 (can apply to all since no digit can be greater than 9 before doubling) 
    # Add up the digits 
    summation <- sum(ifelse(as.numeric(characterVector) > 9, as.numeric(characterVector) - 9, as.numeric(characterVector))) 

    # Take the 10s modulus of the sum, subtract it from 10 and take the 10s modulus of the result 
    # this final step is important in the instance where the modulus of the sum is 0, as the resulting check digit would be 10 
    correctCheckDigit <- (10 - (summation %% 10)) %% 10 == as.numeric(substr(identifier, 12, 12)) 

    correctCheckDigit 

}