Escribe un validador IBAN

8

Escriba un programa (el cuerpo de la función es suficiente) que acepte una cadena de caracteres alfanuméricos y la valide de acuerdo con ISO 13616: 2007. El algoritmo para la validación es (fuente: artículo de Wikipedia en IBAN http://en.wikipedia.org/wiki/International_Bank_Account_Number ):

Validar el IBAN Un IBAN se valida convirtiéndolo en un número entero y realizando una operación básica mod-97 (como se describe en ISO 7064) en él. Si el IBAN es válido, el resto es igual a 1. El algoritmo de validación de IBAN es el siguiente:

  • Verifique que la longitud total de IBAN sea correcta según el país. Si no, el IBAN no es válido. Las longitudes correctas de IBAN se pueden encontrar aquí: http://pastebin.com/kp4eECVk (también se puede encontrar a continuación), ordenadas por la longitud del número IBAN. Los primeros 2 caracteres de cada número es el código del país. Todos los demás caracteres (letras minúsculas en el pastebin, pero pueden ser cualquier caso en el IBAN real) detrás de los primeros 2 pueden ser cualquier carácter alfanumérico.
  • Mueva los cuatro caracteres iniciales al final de la cadena.
  • Reemplace cada letra en la cadena con dos dígitos, expandiendo así la cadena, donde A = 10, B = 11, ..., Z = 35.
  • Interprete la cadena como un entero decimal y calcule el resto de ese número en la división por 97

Si el resto es 1, se pasa la prueba del dígito de verificación y el IBAN podría ser válido.

Ejemplo (banco ficticio del Reino Unido, código de clasificación 12-34-56, número de cuenta 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

El algoritmo moest devuelve verdadero (o un valor verdadero) si el número es válido, y falso (o un valor falso) si el número no es válido según el algoritmo. No necesita verificar si el número realmente existe, solo si es válido. El algoritmo tiene que funcionar para cada uno de los diferentes números de IBAN aprobados mencionados en el artículo de Wikipedia anterior. El algoritmo debe ser compatible con números con o sin caracteres separadores entre 2 caracteres alfanuméricos. El carácter separador puede ser puntos, espacios o guiones y un número puede contener diferentes tipos de separadores.

Se aplican las lagunas habituales: sin recursos externos, sin funciones o métodos integrados.

El tipo de rompecabezas es el código de golf. El código más corto en bytecount gana. La plantilla estándar necesaria para ejecutar el programa (por ejemplo, espacio de nombres, clase, declaración de función en OOP) no se incluye en el bytecount

Bonificación: si puede devolver el número IBAN formateado correctamente (de acuerdo con el formato nacional en wikipedia) en lugar de verdadero en el caso de un número válido, obtendrá una reducción del 25% en su puntaje. Si el número no es válido, devuelve una cadena literal con el valor "Inválido".


Copia de las longitudes de IBAN en caso de que alguna vez se elimine el pastebin:

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
fuente
3
Para quien sugirió agregar etiquetas perl y python: las etiquetas de idioma en los desafíos deben usarse para limitar el desafío a un idioma determinado (o al menos, creo que esa es la intención de ellos). Este desafío está abierto a todos los idiomas. Como tal, rechacé la edición.
Nzall

Respuestas:

4

J (294 - 73.5 = 220.5)

No he contado la definición de la función ( f=:3 :0... )) porque puede considerarse repetitiva, contar todo el bloque da un puntaje de 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-.' -.'
)

Pruebas:

   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

Explicación:

  • b=.y-.' -.': elimina los separadores del argumento y almacena el resultado en b.
  • 1}.;' '&,&.>_4<\b: divídase ben grupos de cuatro, agregue un espacio delante de cada grupo, únase a los grupos y elimine el espacio inicial. Si ycontiene un número IBAN válido, esta es su representación canónica (es decir, grupos de cuatro, separados por espacios, y el último grupo puede tener menos de cuatro elementos).
  • (... ){'Invalid';: cree una matriz con la cadena Invalidcomo elemento 0 y el número IBAN formateado como elemento 1. Seleccione el correcto en función de si el número IBAN es válido:

    • Comprueba la longitud:
      • 'NO.BEBI.---.JOKWU.MT.': una lista de todos los códigos de país para cada longitud, separados por puntos
      • +/"1(2{.b)&E.;.2: agrupe la cadena por los puntos y vea cuál contiene el código de país dado (los primeros 2 elementos de b).
      • 15+1 i.~: encuentra el índice de la coincidencia y suma 15para encontrar la longitud.
      • (#b)=: compárelo con la longitud real de b.
    • Verifica el número:
      • 4|.b: gire ba la izquierda por 4 (reorganizar)
      • k=.3&u:: encuentra el valor ASCII para cada número
      • 48-~k-7*64<k: resta 7 de cada letra, luego resta 48 de todos, dando los valores
      • 1".'x',~' '-.~":: formatee, elimine espacios, agregue una 'x' al final (para el modo de alta precisión, que es necesario para números grandes) y vuelva a convertirlo en un número
      • 1=97|: comprueba si el número mod 97 es igual a 1.
  • >: desempaquetar la cadena resultante
marinus
fuente
4

CJam, 151.5 141.75 puntos

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*?

El programa anterior tiene 189 bytes de longitud y califica para la bonificación.

Con un costo de 26 bytes más, para un puntaje total de 161.25, podemos evitar caracteres no imprimibles:

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*?

Puede probar esta versión en el intérprete de CJam .

Ejecución de ejemplo

$ 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

Cómo funciona

"…"256b27b'@f+"

convierte la cadena "…"en un número entero considerándola un número base 256, luego en una matriz de enteros considerándola un número base 27, agrega el código de caracteres @a cada dígito y los convierte en caracteres en el proceso.

Como resultado, se ejecuta el siguiente código:

" 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
fuente
LANG=en_US java -jar cjam-0.6.2.jar iban.cjam<<<GB82WEST12345698765432salidas no válidas, ¿qué estoy haciendo mal (ejecutándose en Windows8.1 y Cygwin)?
@professorfish: no tengo una computadora con Windows, así que no puedo verificar desde este extremo, pero comencemos verificando lo siguiente: 1. ¿Se generó iban.cjam con éxito? md5sum iban.cjamdebe imprimir 1960c33e31ae5646cd0400826757b3bc. 2. ¿Está la configuración regional instalada correctamente? Puede verificar ejecutando locale -a | grep en_US.
Dennis
No se ha generado correctamente ( fb620d509887f1a7298c3e5ff312401a). locale -a|grep en_USsalidas en_USyen_US.utf8
@professorfish: Interesante. Usted podría intentar esto para evitar el archivo iban.cjam: LANG=en_US cjam <(LANG=en_US cjam gen.cjam) <<< GB82WEST12345698765432. He incluido una versión solo ASCII en mi respuesta que debería ser más fácil de verificar.
Dennis
2

Golpetazo, 738 519 444 434 427

Aquí hay algo para comenzar, lo escribí (y guardé 317 caracteres, principalmente en el bit de almacenamiento del código de país) mientras la pregunta estaba en el sandbox. Avíseme si hay algún problema.

La función se lee desde stdin, que es bastante común en Bash (la pregunta dice "acepta una cadena de caracteres alfanuméricos", no requiere que esto sea a través de argumentos).

Devuelve 0 si el IBAN es válido y un valor distinto de cero si no es válido.

Un IBAN que contiene caracteres distintos de los delimitadores . -y A-Z0-9no es vá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`

Explicación

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`

Ejemplos

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

fuente
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
fuente
WT ?? - Eso es algo de golf! Buen trabajo. Se parece un poco al ruido de la línea desde la distancia ... j / k además es un complemento ;-)
G. Cito
2

Perl (356 + 2 * 75% = 268.5)

el código es tan confuso que incluso el resaltado de sintaxis de SE se pierde en él :)

#!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]

Explicación

#!perl -nl

-nsignifica leer stdin línea por línea; -lagrega nuevas líneas para imprimir

use bignum;

requerido para la operación de módulo más tarde para devolver el valor correcto.

s/\W//g;

eliminar todo lo que no sea \ w de IBAN.

$_=$T=uc;

convierta el número de iban a mayúsculas, también guárdelo en $ T; se usará para imprimir bonitas más tarde.

$q=15;

establezca la variable temporal en 15, se usará para construir una tabla hash con código de país para la asignación de longitud iban.

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

dividir la cadena grande en una matriz de comas o códigos de país de dos letras, iterar sobre ella. si el elemento comienza con una letra, es un código de país: guárdelo en el hash con un valor de $ q; de lo contrario, una coma significa incrementar $ q. entonces, NO obtendrá el valor de 15, BE y BI serán 16, y así sucesivamente.

/../;

coincide con los dos primeros caracteres de IBAN (el código del país)

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

compruebe si IBAN tiene la longitud correcta para el código de país, guarde el resultado en $ q

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

mover los primeros cuatro caracteres al final de IBAN

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

reemplazar todas las letras con los números correspondientes, comenzando con A = 10

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

imprima "Inválido" o el IBAN bonito impreso. 1==$_%97*$qsolo será igual 1para un IBAN con una longitud correcta y el resto correcto.

perl chino goth
fuente
1
¡bonito! En el " perlúnico" subconcurso ganas ;-) Aunque es confuso, ¿podrías intentar explicarlo un poco como en el ejemplo de bash? ¡¿Bastante por favor?! Si explicas el tuyo, explicaré el mío :-) (aunque podría robar uno de tus trucos reales en el país de longitudes IBAN primero). Salud.
G. Cito
2

Perl 6 - 354 caracteres - (no estoy seguro de la bonificación)

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";
}

Leer la entrada de IBANS.txtsobre STDINy sorber las reglas del archivo ir(Salí de las reglas del total en caso de que fueran repetitivo - el archivo de reglas es de 191 caracteres por lo que el total sería de 545.

 perl6 ibanvalidate.p6 IBANS.txt

IBANS.txt es como sigue:

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 el código de país y la longitud y resultados como se muestra a continuación
  • Recuento de caracteres de: wc -m ibanvalidate.p6
  • Actualmente no se realiza la verificación de errores de validación de entrada.
  • El espacio en blanco es significativo en Perl6 (o más significativo que Perl 5), por lo que se cuenta.

Salida 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 no es el código típico de Perl6 (especialmente las comblíneas - un desarrollador de Perl amigable e influyente mencionó esto de pasada): Soy un principiante. Una vez que finalice el concurso, agregaré / cambiaré y haré las modificaciones sugeridas por Perl6-ers. Gracias por jugar y ser amable :-)

G. Cito
fuente
¿Dónde está comprobando el código de país?
@professorfish ... Lo hice en la versión incorrecta de perl ;-) agregará más de 200 caracteres más, estoy seguro.
G. Cito
1

Perl 6 , 311 bytes, puntaje 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/\ .-//}

Pruébalo en línea!

no estoy seguro

  • donde los caracteres separadores se permiten exactamente. Simplemente los elimino a todos.
  • si la salida formateada final debe ser mayúscula.

Explicación

{
  /                # 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
fuente
0

Python3.x (539 caracteres - 25% = 404.25)

(Para decir primero: estoy un poco confundido sobre lo que TIENE que contar con sus reglas, así que solo conté toda mi función)

539 caracteres - Incluyendo importy def IBAN(i):(las pestañas al comienzo de la línea se cuentan de todos modos en Python para que no importen)

Bono aplicado según lo establecido en las reglas.

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 con comentarios (aún no completado ... Estoy demasiado cansado para escribir la parte restante de los comentarios ... Lo haré mañana)

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
fuente
0

Perl (535)

Realmente todavía no estoy jugando al golf, no tengo idea si califico para el bono ;-) Agregaré algunas explicaciones de 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
fuente
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 ")

Pruébalo en línea!

Casos de prueba tomados de la respuesta J de @marinus.

Shieru Asakoto
fuente