

 This page uses content from Wikipedia. The original article was at IBAN. The list of authors can be seen in the page history. As with Rosetta Code, the text of Wikipedia is available under the GNU FDL. (See links for details on variance)



The   International Bank Account Number (IBAN)   is an internationally agreed means of identifying bank accounts across national borders with a reduced risk of propagating transcription errors.

The IBAN consists of up to 34 alphanumeric characters:

   first the two-letter ISO 3166-1 alpha-2 country code, 
   then two check digits, and 
   finally a country-specific Basic Bank Account Number (BBAN). 


The check digits enable a sanity check of the bank account number to confirm its integrity even before submitting a transaction.



Task

Validate the following fictitious IBAN:    GB82 WEST 1234 5698 7654 32 



Details of the algorithm can be found on the Wikipedia page.




{$mode objFPC}
 
uses
	// for delSpace function
	strUtils,
	// GNU multiple-precision library
	GMP;
 
var
	/// this trie contains the correct IBAN length depending on the country code
	IBANLengthInCountry: array['A'..'Z', 'A'..'Z'] of integer;
 
type
	/// Human-readable representation of an IBAN without spaces
	IBANRepresentation = string[34];
 
{
	determines whether an IBANRepresentation is technically potentially correct
 
	\param sample the human-readable IBAN representation
	\return \param sample constains less than the most detectable errors
}
function isLegal(sample: IBANRepresentation): Boolean;
	function checksumCorrect(sample: IBANRepresentation): Boolean;
		type
			digitSequence = string[68];
		function convertLetters(const sequence: IBANRepresentation): digitSequence;
		var
			i: integer;
			transliteration: string[2];
		begin
			// initialize length to zero
			result := '';
 
			for i := 1 to length(sequence) do
			begin
				// by default assume it is a Western-Arabic digit
				transliteration := sequence[i];
 
				// otherwise we’ll need to transliterate the Latin alphabet character
				if not (sequence[i] in ['0'..'9']) then
				begin
					writeStr(transliteration, ord(sequence[i]) - ord('A') + 10);
				end;
 
				// appending transliteration to result also changes the length field
				result := result + transliteration;
			end;
		end;
		var
			i, k: MPInteger;
		begin
			k := 97;
 
			// put first four characters toward end
			writeStr(sample, sample[5..length(sample)], sample[1..4]);
			// interpret converted string as integer to base 10
			Z_set_str(i, convertLetters(sample), 10);
 
			i := Z_mod(i, k);
			k := 1;
			checksumCorrect := Z_cmp(i, k) = 0;
		end;
	begin
		sample := upCase(sample);
		{$push}
			// just for emphasis: by default the FPC performs lazy evaluation
			{$boolEval off}
			isLegal := (length(sample) = IBANLengthInCountry[sample[1], sample[2]])
				and checksumCorrect(sample);
		{$pop}
	end;
 
// === MAIN ==============================================================
begin
	// for the sake of merely achieving the Rosetta Code Task
	IBANLengthInCountry['G', 'B'] := 22;
 
	// note, strings longer than 34 characters will be silently clipped
	writeLn(isLegal(delSpace('GB82 WEST 1234 5698 7654 32')));
end.