Escreva um validador IBAN

8

Escreva um programa (o corpo da função é suficiente) que aceite uma sequência de caracteres alfanuméricos e valide-a de acordo com a ISO 13616: 2007. O algoritmo para validação é (fonte: artigo da wikipedia no IBAN http://en.wikipedia.org/wiki/International_Bank_Account_Number ):

Validando o IBAN Um IBAN é validado convertendo-o em um número inteiro e executando uma operação básica do mod-97 (conforme descrito na ISO 7064) nele. Se o IBAN for válido, o restante será igual a 1. O algoritmo de validação do IBAN é o seguinte:

  • Verifique se o comprimento total do IBAN está correto de acordo com o país. Caso contrário, o IBAN é inválido. Os comprimentos IBAN corretos podem ser encontrados aqui: http://pastebin.com/kp4eECVk (também pode ser encontrado abaixo), ordenados pelo tamanho do número IBAN. os 2 primeiros caracteres de cada número são o código do país. Todos os outros caracteres (letras minúsculas na pasta da pasta, mas podem ser qualquer caso no IBAN real) atrás dos 2 primeiros podem ter qualquer caractere alfanumérico.
  • Mova os quatro caracteres iniciais para o final da string.
  • Substitua cada letra da string por dois dígitos, expandindo a string, onde A = 10, B = 11, ..., Z = 35.
  • Interprete a sequência como um número inteiro decimal e calcule o restante desse número na divisão por 97

Se o restante for 1, o teste do dígito de verificação é aprovado e o IBAN pode ser válido.

Exemplo (banco fictício do Reino Unido, código de classificação 12-34-56, número da conta 98765432):

- IBAN:               GB82 WEST 1234 5698 7654 32 
- Rearrange:          W E S T12345698765432 G B82
- Convert to integer: 3214282912345698765432161182    
- Compute remainder:  3214282912345698765432161182    mod 97 = 1

O algoritmo mais retornará verdadeiro (ou um valor verdadeiro) se o número for válido e falso (ou um valor falso) se o número for inválido de acordo com o algoritmo. Você não precisa verificar se o número realmente existe, apenas se for válido. O algoritmo deve funcionar para cada um dos diferentes números IBAN aprovados mencionados no artigo da Wikipedia acima. O algoritmo deve ser compatível com números com ou sem caracteres separadores entre 2 caracteres alfanuméricos. O caractere separador pode ser pontos, espaços ou traços e um número pode conter diferentes tipos de separadores.

Aplicam-se brechas usuais: sem recursos externos, sem funções ou métodos embutidos.

O tipo de quebra-cabeça é código de golfe. O código mais curto do bytecount vence. O padrão padrão necessário para executar o programa (por exemplo, namespace, classe, declaração de função no OOP) não está incluído no bytecount.

Bônus: se você pode devolver o número IBAN formatado corretamente (de acordo com o formato nacional na wikipedia) em vez de verdadeiro no caso de um número válido, você obtém uma redução de 25% na sua pontuação. Se o número for inválido, você retornará uma sequência literal com o valor "Invalid".


Cópia dos comprimentos de IBAN, caso a pasta seja removida:

Country;Chars;IBAN Fields
Norway;15;NOkk bbbb cccc ccx
Belgium;16;BEkk bbbc cccc ccxx
Burundi;16;BIkk nnnn nnnn nnnn
Denmark;18;DKkk bbbb cccc cccc cc
Faroe Islands;18;FOkk bbbb cccc cccc cx
Finland;18;FIkk bbbb bbcc cccc cx
Greenland;18;GLkk bbbb cccc cccc cc
Netherlands;18;NLkk bbbb cccc cccc cc
Macedonia;19;MKkk bbbc cccc cccc cxx
Slovenia;19;SIkk bbss sccc cccc cxx
Austria;20;ATkk bbbb bccc cccc cccc
Bosnia and Herzegovina;20;BAkk bbbs sscc cccc ccxx
Estonia;20;EEkk bbss cccc cccc cccx
Kazakhstan;20;KZkk bbbc cccc cccc cccc
Lithuania;20;LTkk bbbb bccc cccc cccc
Luxembourg;20;LUkk bbbc cccc cccc cccc
Costa Rica;21;CRkk bbbc cccc cccc cccc c
Croatia;21;HRkk bbbb bbbc cccc cccc c
Latvia;21;LVkk bbbb cccc cccc cccc c
Liechtenstein;21;LIkk bbbb bccc cccc cccc c
Switzerland;21;CHkk bbbb bccc cccc cccc c
Bahrain;22;BHkk bbbb cccc cccc cccc cc
Bulgaria;22;BGkk bbbb ssss ddcc cccc cc
Georgia;22;GEkk bbcc cccc cccc cccc cc
Germany;22;DEkk bbbb bbbb cccc cccc cc
Ireland;22;IEkk aaaa bbbb bbcc cccc cc
Montenegro;22;MEkk bbbc cccc cccc cccc xx
Serbia;22;RSkk bbbc cccc cccc cccc xx
United Kingdom;22;GBkk bbbb ssss sscc cccc cc
Gibraltar;23;GIkk bbbb cccc cccc cccc ccc
Israel;23;ILkk bbbn nncc cccc cccc ccc
United Arab Emirates;23;AEkk bbbc cccc cccc cccc ccc
Andorra;24;ADkk bbbb ssss cccc cccc cccc
Czech Republic;24;CZkk bbbb ssss sscc cccc cccc
Moldova;24;MDkk bbcc cccc cccc cccc cccc
Pakistan;24;PKkk bbbb cccc cccc cccc cccc
Romania;24;ROkk bbbb cccc cccc cccc cccc
Saudi Arabia;24;SAkk bbcc cccc cccc cccc cccc
Slovakia;24;SKkk bbbb ssss sscc cccc cccc
Spain;24;ESkk bbbb gggg xxcc cccc cccc
Sweden;24;SEkk bbbc cccc cccc cccc cccx
Tunisia;24;TNkk bbss sccc cccc cccc cccc
Virgin Islands;24;VGkk bbbb cccc cccc cccc cccc
Algeria;24;DZkk nnnn nnnn nnnn nnnn nnnn
Portugal;25;PTkk bbbb ssss cccc cccc cccx x
Angola;25;AOkk nnnn nnnn nnnn nnnn nnnn n
Cape Verde;25;CVkk nnnn nnnn nnnn nnnn nnnn n
Mozambique;25;MZkk nnnn nnnn nnnn nnnn nnnn n
Iceland;26;ISkk bbbb sscc cccc iiii iiii ii
Turkey;26;TRkk bbbb bxcc cccc cccc cccc cc
Iran;26;IRkk nnnn nnnn nnnn nnnn nnnn nn
France;27;FRkk bbbb bggg ggcc cccc cccc cxx
Greece;27;GRkk bbbs sssc cccc cccc cccc ccc
Italy;27;ITkk xaaa aabb bbbc cccc cccc ccc
Mauritania;27;MRkk bbbb bsss sscc cccc cccc cxx
Monaco;27;MCkk bbbb bsss sscc cccc cccc cxx
San Marino;27;SMkk xaaa aabb bbbc cccc cccc ccc
Burkina Faso;27;BFkk nnnn nnnn nnnn nnnn nnnn nnn
Cameroon;27;CMkk nnnn nnnn nnnn nnnn nnnn nnn
Madagascar;27;MGkk nnnn nnnn nnnn nnnn nnnn nnn
Albania;28;ALkk bbbs sssx cccc cccc cccc cccc
Azerbaijan;28;AZkk bbbb cccc cccc cccc cccc cccc
Cyprus;28;CYkk bbbs ssss cccc cccc cccc cccc
Dominican Republic;28;DOkk bbbb cccc cccc cccc cccc cccc
Guatemala;28;GTkk bbbb cccc cccc cccc cccc cccc
Hungary;28;HUkk bbbs sssk cccc cccc cccc cccx
Lebanon;28;LBkk bbbb cccc cccc cccc cccc cccc
Poland;28;PLkk bbbs sssx cccc cccc cccc cccc
Benin;28;BJkk annn nnnn nnnn nnnn nnnn nnnn
Ivory Coast;28;CIkk annn nnnn nnnn nnnn nnnn nnnn
Mali;28;MLkk annn nnnn nnnn nnnn nnnn nnnn
Senegal;28;SNkk annn nnnn nnnn nnnn nnnn nnnn
Brazil;29;BRkk bbbb bbbb ssss sccc cccc ccct n
Palestinian;29;PSkk bbbb xxxx xxxx xccc cccc cccc c
Qatar;29;QAkk bbbb cccc cccc cccc cccc cccc c
Ukraine;29;UAkk bbbb bbcc cccc cccc cccc cccc c
Jordan;30;JOkk bbbb nnnn cccc cccc cccc cccc cc
Kuwait;30;KWkk bbbb cccc cccc cccc cccc cccc cc
Mauritius;30;MUkk bbbb bbss cccc cccc cccc cccc cc
Malta;31;MTkk bbbb ssss sccc cccc cccc cccc ccc
Nzall
fonte
3
Para quem sugeriu adicionar tags perl e python: as tags de linguagem nos desafios devem ser usadas para limitar o desafio a uma determinada linguagem (ou pelo menos, acho que essa é a intenção delas). Este desafio está aberto a todos os idiomas. Como tal, rejeitei a edição.
Nzall

Respostas:

4

J (294 - 73,5 = 220,5)

Eu não contei a definição da função ( f=:3 :0... )) porque ela pode ser considerada padrão, contando todo o bloco resulta em 304 - 76 = 228 .

f=:3 :0
>((1=97|1".'x',~' '-.~":48-~k-7*64<k=.3&u:4|.b)*(#b)=15+1 i.~+/"1(2{.b)&E.;.2'NO.BEBI..DKFOFIGLNL.MKSI.ATBAEEKZLTLU.CRHRLVLICH.BHBGGEDEIEMERSGB.GIILAE.ADCZMDPKROSASKESSETNVGDZ.PTAOCVMZ.ISTRIR.FRGRITMRMCSMBFCMMG.ALAZCYDOGTHULBPLBJCIMLSN.BRPSQAUA.JOKWMU.MT.'){'Invalid';1}.;' '&,&.>_4<\b=.y-.' -.'
)

Testes:

   NB. invalid numbers
   f ''
Invalid
   f 'GB82 WEST 1234 5698 7654 31'
Invalid
   f 'NL82 WEST 1234 5698 7654 32'
Invalid

   NB. different separators and formatting
   f 'GB82.WEST.1234.5698.7654.32'
GB82 WEST 1234 5698 7654 32
   f 'GB82-WEST-1234-5698-7654-32'
GB82 WEST 1234 5698 7654 32
   f 'GB82WEST12345698765432'
GB82 WEST 1234 5698 7654 32
   f 'GB82 WEST 1234 5698 7654 32'
GB82 WEST 1234 5698 7654 32
   f 'GB.82-WE ST-12.345698.76-5432'
GB82 WEST 1234 5698 7654 32

   NB. wikipedia examples
   f 'GR16 0110 1250 0000 0001 2300 695'
GR16 0110 1250 0000 0001 2300 695
   f 'CH93 0076 2011 6238 5295 7'
CH93 0076 2011 6238 5295 7
   f 'SA03 8000 0000 6080 1016 7519'
SA03 8000 0000 6080 1016 7519
   f 'GB29 NWBK 6016 1331 9268 19'
GB29 NWBK 6016 1331 9268 19

Explicação:

  • b=.y-.' -.': remova qualquer separador do argumento e armazene o resultado em b.
  • 1}.;' '&,&.>_4<\b: divida bem grupos de quatro, adicione um espaço na frente de cada grupo, participe dos grupos e remova o espaço principal. Se ycontinha um número IBAN válido, esta é sua representação canônica (ou seja, grupos de quatro, separados por espaços, com o último grupo talvez tendo menos de quatro elementos).
  • (... ){'Invalid';: crie uma matriz com a sequência Invalidcomo elemento 0 e o número IBAN formatado como elemento 1. Selecione a matriz correta com base na validade do número IBAN:

    • Verifique o comprimento:
      • 'NO.BEBI.---.JOKWU.MT.': uma lista de todos os códigos de país para cada comprimento, separados por pontos
      • +/"1(2{.b)&E.;.2: agrupe a sequência pelos pontos e veja qual deles contém o código do país (os 2 primeiros elementos de b).
      • 15+1 i.~: encontre o índice do correspondente e adicione 15para encontrar o comprimento.
      • (#b)=: verifique com o comprimento real de b.
    • Verifique o número:
      • 4|.b: gire bpara a esquerda 4 (reorganize)
      • k=.3&u:: encontre o valor ASCII para cada número
      • 48-~k-7*64<k: subtraia 7 de cada letra e subtraia 48 de todos, fornecendo os valores
      • 1".'x',~' '-.~":: formate, remova espaços, adicione um 'x' no final (para o modo de alta precisão, necessário para grandes números) e volte a transformá-lo em número
      • 1=97|: verifique se o número mod 97 é igual a 1.
  • >: desmarque a sequência resultante
marinus
fonte
4

CJam, 151,5 141,75 pontos

0000000: 6c22 202e 2d22 2d3a 512c 220f a86e 5136  l" .-"-:Q,"..nQ6
0000010: 1bff 75f6 e8e4 0b35 5dab f190 0d85 59c4  ..u....5].....Y.
0000020: 1938 4366 3d29 5eaa e879 024a 77d9 8baf  .8Cf=)^..y.Jw...
0000030: 5c16 3258 a4d2 4e6c 1a60 429f affa b8f4  \.2X..Nl.`B.....
0000040: 435d e706 457b 89a9 16b8 1d4b 08f7 9970  C]..E{.....K...p
0000050: eeb9 7467 f8e9 c935 33be 2467 3dd4 1afb  ..tg...53.$g=...
0000060: e2ec 20cc 99e4 2783 cb96 512d f9f8 7e75  .. ...'...Q-..~u
0000070: 7066 4307 2232 3536 6232 3762 2740 662b  pfC."256b27b'@f+
0000080: 2740 2f7b 5132 3c23 3126 217d 235f 573e  '@/{Q2<#1&!}#_W>
0000090: 462a 2b3d 5134 6d3c 412c 7327 5b2c 3635  F*+=Q4m<A,s'[,65
00000a0: 3e2b 6623 737e 3937 2531 3d5d 312d 2249  >+f#s~97%1=]1-"I
00000b0: 6e76 616c 6964 2251 342f 532a 3f         nvalid"Q4/S*?

O programa acima tem 189 bytes e se qualifica para o bônus.

Ao custo de mais 26 bytes - para uma pontuação total de 161,25 -, podemos evitar caracteres não imprimíveis:

l" .-"-:Q,",YER,moTd$V6nH\-Mh/I-z(]k!uw()=j9_[C3n&As0(F;TAn$eB-r%:p+^b,1Y.j;thavi@!d,Dt7M_x-5V:#o/m_CKj-c*Imy~IjXPBCo?aM#lrN:[email protected]"33f-94b27b'@f+'@/{Q2<#1&!}#_W>F*+=Q4m<A,s'[,65>+f#s~97%1=]1-"Invalid"Q4/S*?

Você pode testar esta versão no intérprete CJam .

Exemplo de execução

$ cat gen.cjam
"l\" .-\"-:Q,"[32,15>{[
"NO"15"BE"16"BI"16"DK"18"FO"18"FI"18"GL"18"NL"18"MK"19"SI"19
"AT"20"BA"20"EE"20"KZ"20"LT"20"LU"20"CR"21"HR"21"LV"21"LI"21
"CH"21"BH"22"BG"22"GE"22"DE"22"IE"22"ME"22"RS"22"GB"22"GI"23
"IL"23"AE"23"AD"24"CZ"24"MD"24"PK"24"RO"24"SA"24"SK"24"ES"24
"SE"24"TN"24"VG"24"DZ"24"PT"25"AO"25"CV"25"MZ"25"IS"26"TR"26
"IR"26"FR"27"GR"27"IT"27"MR"27"MC"27"SM"27"BF"27"CM"27"MG"27
"AL"28"AZ"28"CY"28"DO"28"GT"28"HU"28"LB"28"PL"28"BJ"28"CI"28
"ML"28"SN"28"BR"29"PS"29"QA"29"UA"29"JO"30"KW"30"MU"30"MT"31
]2/{1=L=},0f=_!!{:+}*}fL]"@"*'@f-27b256b:c`"\\\\"/"\\"*
"256b27b'@f+'@/{Q2<#1&!}#_W>F*+=Q4m<A,s'[,65>+f#s~97%1=]1-\"Invalid\"Q4/S*?"
$ LANG=en_US cjam gen.cjam | tee >(cksum) > iban.cjam
770150303 189
$ LANG=en_US cjam iban.cjam <<< GB82WEST12345698765432; echo
GB82 WEST 1234 5698 7654 32

Como funciona

"…"256b27b'@f+"

converte a seqüência de caracteres "…"em um número inteiro, considerando-o um número de base 256; em seguida, em uma matriz de números inteiros, considerando-o um número de base 27, adiciona o código de caractere de @cada dígito e lança o caractere no processo.

Como resultado, o seguinte código é executado:

" Read one line from STDIN, remove allowed separators, store the result in variable
  “Q” and push its length (“,”).                                                      ";

l" .-"-:Q,

" Push the string from above.
  The correct number of characters for country code “NO” is 15.
  The correct number of characters for country codes “BE” and “BI” is 16.
  The number of characters should never be 17.
  ⋮                                                                                  ";

"NO@BEBI@@DKFOFIGLNL@MKSI@ATBAEEKZLTLU@CRHRLVLICH@BHBGGEDEIEMERSGB@"
"GIILAE@ADCZMDPKROSASKESSETNVGDZ@PTAOCVMZ@ISTRIR@FRGRITMRMCSMBFCMMG@"
"ALAZCYDOGTHULBPLBJCIMLSN@BRPSQAUA@JOKWMU@MT"++

" Split the above string at the at signs (“@”).                                       ";

'@/

" Find the index of the (first) substring such that the index of the country code 
  (“Q2<”) in the substring is even.                                                   ";

{Q2<#1&!}#

" If the country code is invalid, the index will be -1. If the index is greater than 
  -1 (“W>”), add 15 to it; if it isn't, leave -1 on the stack.                        ";

_W>F*+

" Compare the result to the length of the IBAN. Push 1 if they match and 0 otherwise. ";

=

" Push the IBAN rotated to the left by four characters.                               ";

Q4m<

" “A,s'[,65>+” pushes “0123456789ABCDEFGHIJKLMNOPQRSTUVXYZ”. For each character of 
   the IBAN, push its index in that string (-1 if not present).                       ";

A,s'[,65>+f#

" Stringify (“s”) the result, interpret the string (“~”) and compute the residue of
  the (topmost) resulting integer modulo 97.                                          ";

s97%

" Push 1 if the residue is 1; otherwise, push 0                                       ";

1=

" Wrap the entire stack in an array and remove the integer 1 from it. If the IBAN is
  valid, the array will be empty.

" If the result is falsy, the IBAN is valid; split it into substrings of length 4
  and join them using spaces (“S”). Otherwise, the IBAN is invalid; say so.           ";

"Invalid"Q4/S*?
Dennis
fonte
LANG=en_US java -jar cjam-0.6.2.jar iban.cjam<<<GB82WEST12345698765432saídas Inválido, o que estou fazendo de errado (executando no Windows8.1 e Cygwin)?
@professorfish: Eu não tenho um computador Windows, então não posso verificar a partir deste final, mas vamos começar verificando o seguinte: 1. O iban.cjam foi gerado com sucesso? md5sum iban.cjamdeve imprimir 1960c33e31ae5646cd0400826757b3bc. 2. O código do idioma está instalado corretamente? Você pode verificar executando locale -a | grep en_US.
Dennis
Não foi gerado corretamente ( fb620d509887f1a7298c3e5ff312401a). locale -a|grep en_USsaídas en_USeen_US.utf8
@professorfish: Interessante. Você poderia tentar isso para evitar o arquivo iban.cjam: LANG=en_US cjam <(LANG=en_US cjam gen.cjam) <<< GB82WEST12345698765432. Incluí uma versão somente ASCII na minha resposta que deve ser mais fácil de verificar.
Dennis
2

Bater, 738 519 444 434 427

Aqui está algo para começar: eu escrevi (e salvei 317 caracteres, principalmente no bit de armazenamento do código do país) enquanto a pergunta estava na sandbox. Deixe-me saber se há algum problema.

A função lê stdin, o que é bastante comum no Bash (a pergunta diz "aceita uma sequência de caracteres alfanuméricos", não requer que isso seja por meio de argumentos).

Retorna 0 se o IBAN for válido e um valor diferente de zero se for inválido.

Um IBAN contendo caracteres que não sejam os delimitadores . -e A-Z0-9é inválido

t=return
v=`tr -d .\ -`
[ "`tr -dc A-Z0-9<<<$v`" = $v ]||$t
((${#v}>9))||$t
r=`grep -oE "[0-9]+[A-Z]{2}*${v:0:2}"<<<15NO16BEBI18DKFIFOGLNL19MKSI20ATBAEEKZLTLU21CHCRHRLILV22BGBHDEGBGEIEMERS23AEGIIL24ADCZDZESMDPKROSASESKTNVG25AOCVMZPT26IRISTR27BFCMFRGRITMCMGMRSM28BJCICYDOGTHULBMLPLSNAZ29BRPSQAUA30JOKWMU31MT`
[ "${r:0:2}" = ${#v} ]||$t
v=${v:4:99}${v:0:4}
d=({A..Z})
for a in {10..35};{
v=${v//${d[a-10]}/$a}
}
$t `bc<<<$v%97-1`

Explicação

t=return # Alias return to $t
v=`tr -d .\ -` # Remove delimiters from STDIN and save to a variable $v.
# If you want the function to take the IBAN as an argument, insert <<<$1 just before the last ` in the line above
# Check that the number now contains no characters other than A-Z0-9 (i.e. if all other characters are removed, the string should remain the same because there aren't any of them)
# If not, return. By default, return uses the exit status of the previous command, which will be 1
[ "`tr -dc A-Z0-9<<<$v`" = $v ]||$t
# Check that $v is long enough to have a country code at the start, return if not
# I could have put 2 instead of 9, but the character count is the same
((${#v}>9))||$t
# give grep the country code data string, which is of the format <length1><country><country><length2><country><country><country>...
# for example, this tells you that EE has an IBAN length of 20
# grep searches for a number ([0-9]+), followed by any number including zero of country codes ([A-Z]{2}*), followed by the first two characters of the input IBAN, i.e. its country code (${v:0:2})
# -o makes grep only output the match, not the line containing it; -E enables extended regexes
# The result is saved to the variable $r
r=`grep -oE "[0-9]+[A-Z]{2}*${v:0:2}"<<<15NO16BEBI18DKFIFOGLNL19MKSI20ATBAEEKZLTLU21CHCRHRLILV22BGBHDEGBGEIEMERS23AEGIIL24ADCZDZESMDPKROSASESKTNVG25AOCVMZPT26IRISTR27BFCMFRGRITMCMGMRSM28BJCICYDOGTHULBMLPLSNAZ29BRPSQAUA30JOKWMU31MT`
# Check that the length specified by the country code, the first two chars of $r, is equal to the actual IBAN's length ${#v}. return 1 if not.
[ "${r:0:2}" = ${#v} ]||$t
v=${v:4:99}${v:0:4} # Put the first 4 chars to the back
d=({A..Z}) # Make an array of letters A to Z
# Loop for each number from 10 to 35
for a in {10..35};{
# in the IBAN, replace letters A to Z by the corresponding number from 10 to 35
v=${v//${d[a-10]}/$a}
}
# $v is now an integer
# note: I used bc here because Bash's built-in arithmetic couldn't handle big numbers
# find the remainder of dividing $v by 97, subtract 1, and return the value
# if the remainder is 1, then the IBAN is valid and 1-1=0 is returned.
$t `bc<<<$v%97-1`

Exemplos

ibanfn<<<'-GB82-WEST-1234 5698.7654.32    ' #returns 0, valid
ibanfn<<<'-GB82-WEST-1234 5698.7654.33    ' #returns 27, invalid, fails remainder test
ibanfn<<<'GB82 WEST 1234 5698 7654 32a'     #returns 1, invalid, contains invalid character a
ibanfn<<<'YY82 WEST 1234 5698 7654 32'      #returns 1, invalid, country code does not exist
ibanfn<<<'GB82 WEST 1234 5698 7654 3210'    #returns 1, invalid, wrong length

fonte
2

Python 3 - (483 - 25%) 362

import re
def c(i):
 i=re.sub('\W','',i);q,s='NOBEBIDKFOFIGLNLMKSIATBAEEKZLTLUCRHRLVLICHBHBGGEDEIEMERSGBGIILAEADCZMDPKROSASKESSETNVGDZPTAOCVMZISTRIRFRGRITMRMCSMBFCMMGALAZCYDOGTHULBPLBJCIMLSNBRPSQAUAJOKWMUMT',i
 for m in b" !!#####$$%%%%%%&&&&&''''''''((())))))))))))****+++,,,,,,,,,------------....///0":
  if(i[:2],len(i)+17)==(q[:2],m):
   i=i[4:]+i[:4]
   for z in range(26):i=re.sub(chr(65+z),str(z+10),i)
   return(int(i)%97==1)and re.findall('.{,4}',s)or 0
  q=q[2:]
 return 0
LemonBoy
fonte
WT ?? - isso é golfe! Bom trabalho. Parece um pouco como o ruído na linha de uma distância ... j / k além de que é um complemento ;-)
G. Cito
2

Perl (356 + 2 * 75% = 268,5)

o código é tão confuso que até o destaque da sintaxe do SE se perde nele :)

#!perl -ln
use bignum;s/\W//g;$_=$T=uc;$q=15;/\w/?$H{$_}=$q:$q++for'NO,BEBI,,NLGLDKFOFI,SIMK,KZEEATLTLUBA,HRCHLVCRLI,RSIEGEDEBGBHGBME,GIAEIL,SASESKESCZMDTNPKADDZVGRO,PTMZCVAO,TRISIR,CMMGMRSMITFRGRBFMC,ALAZPLCIGTHUSNCYDOBJLBML,UABRQAPS,KWMUJO,MT'=~/,|../g;/../;$q=$H{$&}==y///c;/..../;$_=$'.$&;s/[A-Z]/ord($&)-55/ge;print+(Invalid,join' ',($T=~/.{1,4}/g))[1==$_%97*$q]

Explicação

#!perl -nl

-nsignifica ler stdin linha por linha; -ladiciona novas linhas para imprimir

use bignum;

necessário para a operação do módulo posteriormente para retornar o valor correto.

s/\W//g;

remova tudo o que não é \ w do IBAN.

$_=$T=uc;

converta o número iban em maiúscula, também salve-o em $ T - será usado para imprimir mais tarde.

$q=15;

defina a variável temporária como 15, ela será usada para criar uma tabela de hash com o código do país para o mapeamento de comprimento iban.

/\w/ ? $H{$_}=$q : $q++
for 'NO,BEBI,,NLGLDKFOFI,SIMK,KZEEATLTLUBA,HRCHLVCRLI,RSIEGEDEBGBHGBME,GIAEIL,SASESKESCZMDTNPKADDZVGRO,PTMZCVAO,TRISIR,CMMGMRSMITFRGRBFMC,ALAZPLCIGTHUSNCYDOBJLBML,UABRQAPS,KWMUJO,MT' =~ /,|../g;

divida a string grande em uma matriz de vírgulas ou códigos de país de duas letras e itere sobre ela. se o elemento começa com uma letra, é um código de país - salve-o no hash com um valor de $ q; caso contrário, uma vírgula significa incrementar $ q. então, NO obterá o valor de 15, BE e BI serão 16, e assim por diante.

/../;

corresponde aos dois primeiros caracteres do IBAN (o código do país)

$q=$H{$&}==y///c;

verifique se o IBAN tem o tamanho correto para o código do país, salve o resultado em $ q

/..../;$_=$'.$&; 

mover os quatro primeiros caracteres para o final do IBAN

s/[A-Z]/ord($&)-55/ge;

substitua todas as letras pelos números correspondentes, começando com A = 10

print+(Invalid,join' ',($T=~/.{1,4}/g))[1==$_%97*$q]

imprima "Inválido" ou o IBAN bonito. 1==$_%97*$qserá igual apenas 1para um IBAN com comprimento e restante correto.

gótico chinês do perl
fonte
1
agradável! No perlsubcontesto "único" você vence ;-) Mesmo que seja confuso, você pode tentar explicar um pouco como no exemplo do bash? Muito por favor ?! Se você explica o seu, eu explico o meu :-) (embora eu possa roubar um de seus truques reais, o país comprará o IBAN primeiro). Felicidades.
G. Cito 31/07
2

Perl 6 - 354 caracteres - (não tem certeza do bônus)

my $r = slurp 'ir';
my @cs = $r.comb(/(\D)+/);my @ns = $r.comb(/(\d)+/);
my %h;
for @ns Z @cs -> $n, $c {%h{$n}=[$c.comb(/\w**2/)]};
for my @ =lines() {
 my $o=$_;
 my $y=$_.substr(0,2);
 $_=s:g/\s|\-|\.//.uc.comb.rotate(4).join;
 my $l=$_.chars ; 
 $_.=trans(['A'..'Z'] => ['10'..'35']);
 next if $y !~~ %h{$l}.any;
 say $_%97==1??"$o ok"!!"Invalid";
}

Lendo a entrada de IBANS.txton STDINe sorver as regras do arquivo ir(eu deixei as regras do total no caso de serem clichê - o arquivo de regras é 191 caracteres de modo que o total seria de 545.

 perl6 ibanvalidate.p6 IBANS.txt

IBANS.txt é o seguinte:

GB82 WEST 1234 5698 7654 32
GB82-WEST-1234-5698-7654-32
gb82-west-1234-5698-7654-32
GB82WEST12345698765432
GB82.WEST.1234.5698.7654.32
GR16 0110 1250 0000 0001 2300 695
GB82 WEST 1234 5698 7654 31
NL82 WEST 1234 5698 7654 32
GB29 NWBK 6016 1331 9268 19
Whee perl6
CANADA 000 Banks 007 911

Notas

  • valida o código e o comprimento do país e as saídas conforme abaixo
  • Contagem de caracteres de: wc -m ibanvalidate.p6
  • Atualmente, não há muita validação de verificação de entrada de erro.
  • O espaço em branco é significativo no Perl6 (ou mais significativo que o Perl 5), portanto, é contado.

Saída típica:

GB82 WEST 1234 5698 7654 32 ok
GB82-WEST-1234-5698-7654-32 ok
GB82WEST12345698765432 ok
GB82.WEST.1234.5698.7654.32 ok
GR16 0110 1250 0000 0001 2300 695 ok
Invalid
GB29 NWBK 6016 1331 9268 19 ok

Este não é um código Perl6 típico (especialmente as comblinhas que um desenvolvedor de Perl amigável e influente mencionou isso de passagem): Eu sou iniciante. Quando o concurso terminar, adicionarei / alterarei e faço as modificações sugeridas pelos Perl6-ers. Obrigado por jogar e ser legal :-)

G. Cito
fonte
Onde está a verificação do código do país?
@professorfish ... Eu fiz isso na versão errada do perl ;-) ele adicionará mais de 200 caracteres, tenho certeza.
G. Cito 29/07
1

Perl 6 , 311 bytes, pontuação 233,25

{/:i^(..)<[A..Z0..9]>+$/&&'NobeBIdkfofiglNlmkSiatbaeekzltLucrhrlvliChbhbggedeiemersGbgiilAeadczmdpkrosaskessetnvgDzptaocvMzistrIrfrgritmrmcsmbfcmMgalazcydogthulbplbjcimlSnbrpsqaUajokwMumt'~~/^:i(..)*$($0)/&&.comb==$0.comb(/<:Lu>/)+15&&[.comb].rotate(4)>>.&{:36($_)}.join%97==1&&~.comb(4)||'Invalid'}o{TR/\ .-//}

Experimente online!

Não tenho certeza

  • onde caracteres separadores são permitidos exatamente. Eu simplesmente removo todos eles.
  • se a saída final formatada deve estar em maiúscula.

Explicação

{
  /                # Match against regex
    :i             #   ignore case
    ^              #   start of string
    (..)           #   country code (stored in $0)
    <[A..Z0..9]>+  #   alphanumeric characters
    $              #   end of string
  /
  &&
  'NobeBIdk...'    # Country code string with uppercase letter
                   # for each length increase
  ~~               # match against
  /                # regex
    :i             #   ignore case
    ^              #   start of string
    (..)*          #   series of two characters (stored in $0)
    $($0)          #   country code
  /
  &&
  .comb==          # IBAN length equals
  $0.comb(/<:Lu>/) # number of uppercase characters
  +15              # plus 15
  &&
  [.comb]          # Split IBAN into characters
  .rotate(4)       # Rotate by four
  >>.&{:36($_)}    # Convert each from base-36
  .join            # Join
  %97==1           # Modulo 97 check
  &&
  ~.comb(4)        # Add space after every four characters
  ||
  'Invalid'        # Return 'Invalid' if any of the checks failed
}
o                  # Function composition
{
  TR/\ .-//        # Remove space, dot, dash
}
Nwellnhof
fonte
0

Python3.x (539 caracteres - 25% = 404,25)

(Para ser dito primeiro: estou um pouco confuso com o que as regras devem contar para você, então contei toda a minha função)

539 caracteres - Incluindo importe def IBAN(i):(as guias no início da linha são contadas de qualquer maneira em python para que não importem)

Bônus aplicado conforme estabelecido nas regras.

def IBAN(i):
    import re
    i=re.sub(r'[^\w]','',i).upper()
    k=len(i)
    z=i[:2]in re.search(r'%s([A-Z ]*)'%k,'15NO16BE BI18DK FO FI GL NL19MK SI20AT BA ES KZ LT LU21CR HR LV LI CH22BH BG GE DE IE MK RS GB23GI IL AE24MD PK RO SA SK ES SE TN VG DZ25CV MZ26IS TR IR FR GR IT MR MC SM BF CM MG28AL AZ CY DO GT HU LB PL BJ CI ML SN29BR PS QA UA30JO KW MU31MT').group(1)or None
    if int(''.join([c if c.isdigit()else str(ord(c)-55)for c in i[4:]+i[:4]]))%97!=1 or z is None:return('Invalid')
    return(' '.join([i[0+j:4+j]for j in range(0,k,4)]))

Código com comentários (ainda não concluído ... Estou cansado demais para escrever a parte restante dos comentários ... farei isso amanhã)

def IBAN(i):
    import re
    # Remove all non word characters (including space) and change to uppercase
    # as0098-7*46.76A -> AS009874676A
    i=re.sub(r'[^\w]','',i).upper()
    # Get the length of it because I need it later multiple times
    k=len(i)
    #                   r'%s([A-Z ]*)'%k = Replace %s with the length of i
    #         re.search(                ,'15NO16BE BI18DK FO FI GL NL19MK SI20AT BA ES KZ LT LU21CR HR LV LI CH22BH BG GE DE IE MK RS GB23GI IL AE24MD PK RO SA SK ES SE TN VG DZ25CV MZ26IS TR IR FR GR IT MR MC SM BF CM MG28AL AZ CY DO GT HU LB PL BJ CI ML SN29BR PS QA UA30JO KW MU31MT')
    #                                    = search (with regexp) in this string (which are the lengths and countrycodes seperated by space)
    # Return the first found match (scroll to the right to see)                                                                                                                                                                                                                                .group(1)
    # i[:2]in                                                                                                                                                                                                                                                                                           or None
    # = The first two characters in the returned string (in the same order and same case)
    z=i[:2]in re.search(r'%s([A-Z ]*)'%k,'15NO16BE BI18DK FO FI GL NL19MK SI20AT BA ES KZ LT LU21CR HR LV LI CH22BH BG GE DE IE MK RS GB23GI IL AE24MD PK RO SA SK ES SE TN VG DZ25CV MZ26IS TR IR FR GR IT MR MC SM BF CM MG28AL AZ CY DO GT HU LB PL BJ CI ML SN29BR PS QA UA30JO KW MU31MT').group(1)or None
    if int(''.join([c if c.isdigit()else str(ord(c)-55)for c in i[4:]+i[:4]]))%97!=1 or z is None:return('Invalid')
    return(' '.join([i[0+j:4+j]for j in range(0,k,4)]))
chill0r
fonte
0

Perl (535)

Ainda não jogou golfe de verdade - não faço ideia se me qualifico para o bônus ;-) adicionarei algumas explicações do tipo @professorfish.

#!perl -ln
$r="15NO16BEBI18DKFIFOGLNL19MKSI20ATBAEEKZLTLU21CHCRHRLILV22BGBHDEGBGEIEMERS23AEGIIL24ADCZDZESMDPKROSASESKTNVG25AOCVMZPT26IRISTR27BFCMFRGRITMCMGMRSM28BJCICYDOGTHULBMLPLSNAZ29BRPSQAUA30JOKWMU31MT";
$c{$1} = [unpack("(A2)*", $2)] while($r) =~/(\d{2})(\D{2,})/g; 
@h{("A".."Z")}=(10..35);
chomp;$o=$_;$_=uc$_;
s/[ -.]//g;
$l=y///c;
($m)=($_=~m/^.{2}/g);
($n=$_) =~s/^(....)(.*)/$2$1/dg;
$n=~s/([A-Z])/$h{$1}/g;
print $m ~~ @{$c{$l}} ? "length valid for $m":"invalid length"; 
use bignum;
print $n%97==1 ? "$o ok":"$o Invalid";
G. Cito
fonte
0

JavaScript (Node.js) , 372 bytes * .75 = 279

s=>(s=s[R="replace"](/[^A-Z0-9]/g,"")).length-14-"NO|BEBI||DKFOFIGLNL|MKSI|BATEEKZLTLU|CRCHRLVLI|GBHBGEDEIEMERS|GILAE|SADCZMDZPKROSASKESETNVG|PTAOCVMZ|ISTRIR|BFRGRITSMRMCMG|ALBJAZCYDOGTHUPLCIMLSN|BRPSQAUA|JOKWMU|MT".match(eval(`/.*${s.slice(0,2)}/i`))[0].split`|`.length||BigInt((s.slice(4)+s.slice(0,4))[R](/\w/g,x=>parseInt(x,36)))%97n-1n?"Invalid":s[R](/(.{4})/g,"$1 ")

Experimente online!

Casos de teste emprestados da resposta J de @marinus.

Shieru Asakoto
fonte