Jeśli się nie mylę, numery ISIN na ostatniej pozycji to cyfra weryfikacyjna. Jaka jest funkcja matematyczna, która określa jej wartość w funkcji pierwszych 11 cyfr?Jak potwierdzić numer międzynarodowego identyfikatora papierów wartościowych (ISIN)
Odpowiedz
http://en.wikipedia.org/wiki/International_Securities_Identification_Number
Procedura wyliczania ISIN cyfry kontrolne jest podobna do techniki "Moduł 10 Podwójne Dodaj double" użytego w CUSIPs. Aby obliczyć cyfrę kontrolną, najpierw przekonwertuj dowolne litery na cyfry, dodając ich pozycję porządkową w alfabecie do 9, tak, aby A = 10 i M = 22. Zaczynając od prawej najbardziej cyfry, każda inna cyfra jest pomnożona przez dwa. (W przypadku cyfr sprawdzania CUSIP te dwa kroki są odwrócone). Wynikowy ciąg cyfr (liczby większe niż 9, które stają się dwiema oddzielnymi cyframi), są sumowane. Odejmij tę sumę od najmniejszej liczby kończącej się na zero, która jest większa lub równa: daje to cyfrę kontrolną, która jest również znana jako dziesiąte uzupełnienie sumy modulo 10. Oznacza to, że suma wynikowa, w tym suma kontrolna cyfra jest wielokrotnością liczby 10.
Mają także good example.
podstawie przykładów opublikowanego w Wikipedia, sposób jest:
- Wymiana każdej litery jego porządkowej (A = 1, B = 2 i tak dalej) oraz 9 ->
- Dla każdego cyfrę w równej pozycji, zaczynając od skrajnej prawej pozycji (
), zastępując ją cyframi jej podwójnej (dwie cyfry w dwóch wektorach) ->
; Kod
- kontrolny:
Ewentualna realizacja w JavaScript jest:
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);
}
EDIT: Aby dołączyć @queso aktualizacji:
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
}
Dla powyższego kodu ISIN XS0977502110 nie może znaleźć tutaj: http://en.wikipedia.org/wiki/International_Securities_Identification_Number#External_links Udało mi się zaktualizować kod tutaj http://jsfiddle.net/markbenda/nh2w1Lbh/16/. Dzięki za trudną część. – Queso
@Queso Edytowałem swoją odpowiedź, aby uwzględnić sugestie dotyczące kodu. Dzięki za ulepszenia! –
Building na przykładach innych, tutaj jest implementacja C#, która będzie sprawdzać zarówno numery ISIN, jak i CUSIP (i być może niektóre inne odmiany Luhna).
Zastosowanie:
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);
}
Realizacja:
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;
}
}
Będzie to prawdopodobnie sensu używać sprawdzania sum kontrolnych w połączeniu z regularnym meczu wzór ekspresji. Są regex używam:
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]$
Chciałbym podzielić się moją implementację w R. nie wymaga żadnego konkretnego pakietu.
MGsub to funkcja wsparcia, która pozwala na zamianę wszystkich znaków w kodzie ISIN za pomocą jednego polecenia. Jest on skopiowany z Replace multiple letters with accents with gsub
iso3166alpha2$Code
zawiera listę krajów, które Grenade wymienia
Algorytm jest realizowany w funkcji isIsin(x)
, która zwraca TRUE
w przypadku ważnego kodu 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
}
tego opisu ma kilka błędów: "... każda inna cyfra jest pomnożona przez dwa". Jak mogłem znaleźć w innych odnośnikach i sprawdzeniu przykładów: Nie każdy inny numer, ale alternatywne cyfry są mnożone przez dwa. –
@ PabloFranciscoPérezHidalgo: całkowicie uzasadnione jest interpretowanie "każdej innej cyfry" jako "alternatywnej cyfry". Nie jest jasne, co myślisz o błędach w wpisie do Wikipedii. –