Validate International Securities Identification Number: Difference between revisions

Tag: Manual revert
 
(19 intermediate revisions by 9 users not shown)
Line 543:
1 FR0000988040
</pre>
 
=={{header|BASIC256}}==
<syntaxhighlight lang="vbnet">array base 1
 
dim test_set$(7)
test_set$ = {"US0378331005", "US0373831005", "U50378331005", "US03378331005", "AU0000XVGZA3", "AU0000VXGZA3", "FR0000988040"}
 
for i = 1 to test_set$[?]
test_str$ = ""
l = length(test_set$[i])
if l <> 12 then
print test_set$[i]; " Invalid, length <> 12 char."
continue for
end if
if asc(mid(test_set$[i], 1, 1)) < asc("A") or asc(mid(test_set$[i], 2, 1)) < asc("A") then
print test_set$[i]; " Invalid, number needs to start with 2 characters"
continue for
end if
for n = 1 to l
x = asc(mid(test_set$[i], n, 1)) - asc("0")
if x > 9 then x -= 7
if x < 10 then
test_str$ += string(x)
else # two digest number
test_str$ += string(x \ 10) + string(x mod 10)
end if
next
print test_set$[i]; " ";
if luhntest(test_str$) = 1 then
print "Invalid, checksum error"
else
print "Valid"
end if
next
end
 
function luhntest(cardnr$)
cardnr$ = trim(cardnr$) # remove spaces
l = length(cardnr$)
s1 = 0
s2 = 0
 
# sum odd numbers
for i = 1 to l step 2
s1 += fromradix(asc(mid(cardnr$, i, 1)), 10)
next
# sum even numbers
for i = 2 to l step 2
j = fromradix(asc(mid(cardnr$, i, 1)), 10)
j *= 2
if j > 9 then j = (j mod 10) + 1
s2 += j
next
 
return (s1 + s2) mod 10 = 0
end function</syntaxhighlight>
{{out}}
<pre>Similar to FreeBASIC entry.</pre>
 
=={{header|Bruijn}}==
Using bruijn's <code>luhn</code> solution from [[Luhn test of credit card numbers]]:
<syntaxhighlight lang="bruijn">
:import luhn_test_of_credit_card_numbers .
 
:import std/Number/Conversion .
:import std/Combinator .
:import std/String .
:import std/Char .
:import std/Logic .
:import std/Number .
 
# verifies ISIN format
format? [len ⋀? country ⋀? security ⋀? checksum]
len (length 0) =? (+12)
country all? uppercase? (take (+2) 0)
security all? (φ or? uppercase? numeric?) (take (+9) (drop (+2) 0))
checksum numeric? _0
 
# performs luhn test
checksum? (map (from-base36 → number→string)) → concat → string→number → luhn
from-base36 binary→ternary → [(0 - (0 ≥? (+65) ((+65) - (+10)) (+48)))]
 
# performs format and checksum test
validate φ and? format? checksum?
 
:test (validate "US0378331005") (true)
:test (validate "US0373831005") (false)
:test (validate "U50378331005") (false)
:test (validate "US03378331005") (false)
:test (validate "AU0000XVGZA3") (true)
:test (validate "AU0000VXGZA3") (true)
:test (validate "FR0000988040") (true)
</syntaxhighlight>
 
=={{header|C}}==
Line 1,080 ⟶ 1,173:
AU0000VXGZA3 is valid
FR0000988040 is valid</pre>
 
=={{header|Dart}}==
<syntaxhighlight lang="dart">bool checkISIN(String isin) {
int j = 0, v = 0;
List<int> s = List.filled(24, 0);
 
for (int i = 0; i < 12; i++) {
int k = isin.codeUnitAt(i);
if (k >= '0'.codeUnitAt(0) && k <= '9'.codeUnitAt(0)) {
if (i < 2) return false;
s[j++] = k - '0'.codeUnitAt(0);
} else if (k >= 'A'.codeUnitAt(0) && k <= 'Z'.codeUnitAt(0)) {
if (i == 11) return false;
k -= 'A'.codeUnitAt(0) - 10;
s[j++] = k ~/ 10;
s[j++] = k % 10;
} else {
return false;
}
}
 
if (isin.length > 12) return false;
 
for (int i = j - 2; i >= 0; i -= 2) {
int k = 2 * s[i];
v += k > 9 ? k - 9 : k;
}
 
for (int i = j - 1; i >= 0; i -= 2) {
v += s[i];
}
 
return v % 10 == 0;
}
 
void main() {
List<String> test = [
"US0378331005",
"US0373831005",
"U50378331005",
"US03378331005",
"AU0000XVGZA3",
"AU0000VXGZA3",
"FR0000988040"
];
 
for (String isin in test) {
print('$isin - ${checkISIN(isin)}');
}
}</syntaxhighlight>
{{out}}
<pre>US0378331005 - true
US0373831005 - false
U50378331005 - false
US03378331005 - false
AU0000XVGZA3 - true
AU0000VXGZA3 - true
FR0000988040 - true</pre>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
 
 
<syntaxhighlight lang="Delphi">
 
 
function StrToBase10(S: string): TByteDynArray;
{Convert ASCII string to Base-10}
{ASCII Digits converted to integer 0..9 }
{ASCII Chars convert to bytes "A"=10, "B"=11, etc }
var I: Integer;
var B: byte;
 
procedure StoreByte(B: byte);
begin
SetLength(Result,Length(Result)+1);
Result[High(Result)]:=B;
end;
 
begin
SetLength(Result,0);
for I:=1 to Length(S) do
begin
if S[I] in ['0'..'9'] then StoreByte(Byte(S[I])-$30)
else
begin
B:=(Byte(S[I])-$41)+10;
StoreByte(B div 10);
StoreByte(B mod 10);
end;
end;
end;
 
{Simplifies cases where we have to sum a two digit number}
 
const DigitSum: array [0..18] of byte = (0,1,2,3,4,5,6,7,8,9,1,2,3,4,5,6,7,8,9);
 
function LuhnTest(Nums: array of byte): boolean;
{Perform Luhn Test of byte array}
var I,J,Len,Sum,Sum1,Sum2: integer;
var Rev: array of byte;
begin
Sum1:=0; Sum2:=0;
Len:=High(Nums);
for I:=Len downto 0 do
if ((I-Len) and 1)=0 then Sum1:=Sum1 + Nums[I]
else Sum2:=Sum2 + DigitSum[Nums[I]*2];
Sum:=Sum1+Sum2;
Result:=(Sum mod 10)=0;
end;
 
{String error types}
 
type TStringErrors = (seNone,seLength,seCountry);
 
function ValidateStr(IDStr: string): TStringErrors;
{Validate string checking for incorrectly length}
{And invalid country code}
begin
if Length(IDStr)<>12 then Result:=seLength
else if not (IDStr[1] in ['a'..'z','A'..'Z']) or
not (IDStr[2] in ['a'..'z','A'..'Z']) then Result:=seCountry
else Result:=seNone;
end;
 
 
 
procedure ValidateID(Memo: TMemo; IDStr: string);
{Validate and display status of string}
var BA: TByteDynArray;
var LT: boolean;
var SE: TStringErrors;
var S: string;
begin
SE:=ValidateStr(IDStr);
BA:=StrToBase10(IDStr);
LT:=LuhnTest(BA);
if LT and (SE=seNone) then Memo.Lines.Add(IDStr+': Valid')
else
begin
S:=IDStr+': Invalid';
if not LT then S:=S+', Luhn Error';
case SE of
seLength: S:=S+', Length Error';
seCountry: S:=S+', Country Code Error';
end;
Memo.Lines.Add(S);
end;
end;
 
 
 
procedure ValidateSecuritiesID(Memo: TMemo);
var BA: TByteDynArray;
var I: integer;
var S: string;
begin
ValidateID(Memo,'US0378331005');
ValidateID(Memo,'US0373831005');
ValidateID(Memo,'U50378331005');
ValidateID(Memo,'US03378331005');
ValidateID(Memo,'AU0000XVGZA3');
ValidateID(Memo,'AU0000VXGZA3');
ValidateID(Memo,'FR0000988040');
end;
 
 
 
</syntaxhighlight>
{{out}}
<pre>
US0378331005: Valid
US0373831005: Invalid, Luhn Error
U50378331005: Invalid, Country Code Error
US03378331005: Invalid, Length Error
AU0000XVGZA3: Valid
AU0000VXGZA3: Valid
FR0000988040: Valid
 
Elapsed Time: 6.863 ms.
 
</pre>
 
 
=={{header|EasyLang}}==
{{trans|AWK}}
<syntaxhighlight>
func isin t$ .
if len t$ <> 12
return 0
.
for i to 12
k = strcode substr t$ i 1
if k >= 48 and k <= 57
if i <= 2
return 0
.
s[] &= k - 48
elif k >= 65 and k <= 91
if (i = 12)
return 0
.
k -= 55
s[] &= k div 10
s[] &= k mod 10
else
return 0
.
.
i = len s[] - 1
while i >= 1
k = 2 * s[i]
if k > 9
k -= 9
.
v += k
i -= 2
.
i = len s[]
while i >= 1
v += s[i]
i -= 2
.
if v mod 10 = 0
return 1
.
.
test$[] = [ "US0378331005" "US0373831005" "U50378331005" "US03378331005" "AU0000XVGZA3" "AU0000VXGZA3" "FR0000988040" ]
for t$ in test$[]
if isin t$ = 1
print t$ & " is valid"
else
print t$ & " is invalid"
.
.
</syntaxhighlight>
{{out}}
<pre>
US0378331005 is valid
US0373831005 is invalid
U50378331005 is invalid
US03378331005 is invalid
AU0000XVGZA3 is valid
AU0000VXGZA3 is valid
FR0000988040 is valid
</pre>
 
=={{header|Elixir}}==
Line 1,762 ⟶ 2,102:
 
=={{header|langur}}==
The luhn test is repeated here for simplicity (from Luhn_test_of_credit_card_numbers#langur).
 
<syntaxhighlight lang="langur">
{{works with|langur|0.8.10}}
<syntaxhighlight lang="langur">val .luhntest = ffn(.s) {
val .t = [0, 2, 4, 6, 8, 1, 3, 5, 7, 9]
val .numbers = s2n .s -> s2n
val .oddeven = len(.numbers) rem 2
 
for[=0] .i of .numbers {
_for += if(. i rem 2 == .oddeven: .numbers[.i]; .t[.numbers[.i]+1]){
numbers[i]
} else {
t[numbers[i]+1]
}
} div 10
}
 
val .isintest = ffn(.s) {
matching(s -> re/^[A-Z][A-Z][0-9A-Z]{9}[0-9]$/, .s) and
.luhntest(joins -> s2n .s)-> join -> luhntest
}
 
val .tests = h{
"US0378331005": true,
"US0373831005": false,
Line 1,790 ⟶ 2,134:
}
 
for .key in sort(keys .(tests)) {
val .pass = .isintest(.key)
write .key, ": ", .pass
writeln if(.pass == .tests[.key]: ""; " (ISIN TEST FAILED)")
}
}</syntaxhighlight>
</syntaxhighlight>
 
{{out}}
Line 2,359 ⟶ 2,704:
 
=={{header|REXX}}==
<syntaxhighlight lang="rexx">/*REXX program validates the checksum digit for an International Securities ID number.*/
parse/*REXX argprogram zvalidates International Securities ID numbers. /*obtain optional ISINs from the C.L.*/
Parse Arg z /*obtain ISINs from the C.L. */
if z='' then z= "US0378331005 US0373831005 U50378331005 US03378331005 AU0000XVGZA3" ,
If z='' Then 'AU0000VXGZA3 FR0000988040' /* [?] use the default list of ISINs. */
z='US0378331005 US0373831005 U50378331005 US03378331005',
/* [↓] process all specified ISINs.*/
'US037*331005',
do n=1 for words(z); x=word(z, n); y= x /*obtain an ISIN from the Z list. */
'XY037833100Z AU0000XVGZA3 AU0000VXGZA3 FR0000988040'
$= /* [↓] construct list of ISIN digits. */
valid='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' /*X must contain 0-->9 A-->Z */
do k=1 for length(x); _= substr(x,k,1) /*the ISIN may contain alphabetic chars*/
Do n=1 To words(z) /* [?] process all specified ISINs.*/
p= pos(_, 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ) /*X must contain A──►Z, 0──►9.*/
x=word(z,n) if p==0 then y= /*obtain an ISIN from the Z list. /*trigger "not" valid below.*/
p=verify(x,valid,'N')
else $= $ || p-1 /*convert X string (base 36 ──► dec).*/
If p>0 Then msg='invalid character in position' p':' substr(x,p,1)
end /*k*/ /* [↑] convert alphabetic ──► digits.*/
Else Do
@= /*placeholder for the "not" in message.*/
dd='' if length(y)\==12 then @= "not" /*see if[?] the ISINconstruct islist exactlyof 12ISIN charsdigits. */
Do k=1 To length(x)
if \datatype( left(x,2),'U') then @= "not" /* " " " " 1st 2 chars cap. let.*/
if \datatype(right_=substr(x,k,1),'W') then @= "not" /* " " " " last char not a digit /*the ISIN may contain alphabetic chars*/
if @ p==''pos(_,valid) then if \luhn($) then @= "not" /*X contains 0-->9 A-->Z " " " " passed the Luhn test.*/
say right(x,dd=dd||p-1 30) right(@, 5) "valid" /*display the yea or nay message /*convert X string (base 36 --? dec).*/
End
end /*n*/ /* [↑] 1st 3 IFs could've been combined*/
msg=''
exit /*stick a fork in it, we're all done. */
Select
/*──────────────────────────────────────────────────────────────────────────────────────*/
When length(x)\==12 Then msg='not exactly 12 chars'
Luhn: procedure; parse arg x; $= 0 /*get credit card number; zero $ sum. */
y=When reverse\datatype( left(0x, length(x) // 2)x,'U') Then msg='not starting with 2 /*add leading zero if needed, &capital reverse*/chars'
When \datatype(right(x,1),'W') Then msg='last character is not a digit'
do j=1 to length(y)-1 by 2; _= 2 * substr(y, j+1, 1)
Otherwise
$= $ + substr(y, j, 1) + left(_, 1) + substr(_, 2 , 1, 0)
If \luhn(dd) Then msg='does endnot /*j*/ /* [↑] sumpass the Luhn odd and even digits.*/test'
End
return right($, 1)==0 /*return "1" if number passed Luhn test*/</syntaxhighlight>
End
If msg='' Then
Say right(x,15) ' valid' /* display the positive message. */
Else
Say right(x,15) 'not valid:' msg /* display the problem */
End /*n*/
Exit /*stick a fork in it, we're all done */
/*-----------------------------------------------------------------------------------*/
luhn: Procedure
Parse Arg x /* get credit card number; */
dsum=0 /* zero digit sum. */
y=reverse(left(0,length(x)//2)x) /* add leading zero If needed & reverse */
Do j=1 To length(y)-1 By 2
_=2*substr(y,j+1,1)
dsum=dsum+substr(y,j,1)+left(_,1)+substr(_,2,1,0)
End
Return right(dsum,1)==0 /* Return 1 if number passed Luhn test */</syntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
US0378331005 valid
US0373831005 not valid: does not pass the Luhn test
US0373831005 not valid
U50378331005 not valid: not starting with 2 capital chars
U50378331005 not valid
US03378331005 not valid: not exactly 12 chars
US03378331005 not valid
US037*331005 not valid: invalid character in position 6: *
AU0000XVGZA3 valid
XY037833100Z not valid: last character is not a digit
AU0000VXGZA3 valid
FR0000988040 AU0000XVGZA3 valid
AU0000VXGZA3 valid
FR0000988040 valid
</pre>
 
Line 2,489 ⟶ 2,853:
AU0000VXGZA3 -> Valid
FR0000988040 -> Valid
</pre>
 
=={{header|RPL}}==
<code>LUHN?</code> is defined at [[Luhn test of credit card numbers#RPL|Luhn test of credit card numbers]]
{{works with|RPL|HP48-R}}
« '''IF''' DUP SIZE 12 ≠ '''THEN''' DROP 0
'''ELSE'''
""
1 3 PICK SIZE '''FOR''' j
OVER j DUP SUB
'''IF''' "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" SWAP POS '''THEN''' LASTARG 1 - + '''END'''
'''NEXT'''
<span style="color:blue">LUHN?</span>
{ "AD" "AT" "AU" "BE" "CA" "DE" "ES" "FR" "GB" "HK" "IT" "US" "ZW" } <span style="color:grey">@ country codes sample </span>
ROT 1 2 SUB POS AND
'''END'''
» '<span style="color:blue">ISIN?</span>' STO
 
{"US0378331005" "US0373831005" "U50378331005" "US03378331005" "AU0000XVGZA3" "AU0000VXGZA3" "FR0000988040"}
1 « <span style="color:blue">ISIN?</span> » DOLIST
{{out}}
<pre>
1: { 1 0 0 0 1 1 1 }
</pre>
 
Line 2,904 ⟶ 3,291:
</syntaxhighlight>
 
=={{header|Uiua}}==
<syntaxhighlight lang="uiua">
Base ← "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Luhn ← =0◿10+⊃(/+⊢|/+∵(⍥(-9)>9.×2)⊡1)⍉⬚0↯∞_2⇌
Checksum ← Luhn≡⋕/◇⊂≡(□°⋕⊗)⊙(¤Base)
Format ← ××⊃(/×≡(≥@A)↙2|=12⧻|/↧∊:Base)
Valid ← ×⊃(Format|Checksum)
 
Tests ← {
"AU0000XVGZA3"
"US0378331005"
"US0373831005" # twiddled
"U50378331005" # 5 rather than S
"US03378331005" # Extra char
"AU0000XVGZA3"
"AU0000VXGZA3"
"FR0000988040"
"F00Ö00988040" # Illegal char
}
 
≡◇Valid Tests
</syntaxhighlight>
{{out}}
<pre>
[1 1 0 0 0 1 1 1 0]
</pre>
=={{header|VBScript}}==
<syntaxhighlight lang="vb">' Validate International Securities Identification Number - 03/03/2019
Line 3,124 ⟶ 3,537:
=={{header|Wren}}==
{{libheader|Wren-str}}
{{libheader|Wren-traititerate}}
{{libheader|Wren-fmt}}
The Luhn test method is reproduced here for convenience.
<syntaxhighlight lang="ecmascriptwren">import "./str" for Char
import "./traititerate" for Stepped
import "./fmt" for Conv, Fmt
 
var luhn = Fn.new { |s|
1,007

edits