Task: IBAN


C++: #include <string>
#include <iostream>
#include <boost/algorithm/string.hpp>
#include <map>
#include <algorithm>
#include <cctype>

using namespace boost::algorithm;

bool isValid(const std::string &ibanstring) {
    static std::map<std::string, int> countrycodes {
        {"AL", 28}, {"AD", 24}, {"AT", 20}, {"AZ", 28 },
        {"BE", 16}, {"BH", 22}, {"BA", 20}, {"BR", 29 },
        {"BG", 22}, {"CR", 21}, {"HR", 21}, {"CY", 28 },
        {"CZ", 24}, {"DK", 18}, {"DO", 28}, {"EE", 20 },
        {"FO", 18}, {"FI", 18}, {"FR", 27}, {"GE", 22 },
        {"DE", 22}, {"GI", 23}, {"GR", 27}, {"GL", 18 },
        {"GT", 28}, {"HU", 28}, {"IS", 26}, {"IE", 22 },
        {"IL", 23}, {"IT", 27}, {"KZ", 20}, {"KW", 30 },
        {"LV", 21}, {"LB", 28}, {"LI", 21}, {"LT", 20 },
        {"LU", 20}, {"MK", 19}, {"MT", 31}, {"MR", 27 },
        {"MU", 30}, {"MC", 27}, {"MD", 24}, {"ME", 22 },
        {"NL", 18}, {"NO", 15}, {"PK", 24}, {"PS", 29 },
        {"PL", 28}, {"PT", 25}, {"RO", 24}, {"SM", 27 },
        {"SA", 24}, {"RS", 22}, {"SK", 24}, {"SI", 19 },
        {"ES", 24}, {"SE", 24}, {"CH", 21}, {"TN", 24 },
        {"TR", 26}, {"AE", 23}, {"GB", 22}, {"VG", 24 }
    };
    std::string teststring(ibanstring);
    erase_all(teststring, " "); 
    if (countrycodes.find(teststring.substr(0, 2)) == countrycodes.end())
        return false;
    if (teststring.length() != countrycodes[teststring.substr(0, 2)])
        return false;
    if (!all(teststring, is_alnum()))
        return false;
    to_upper(teststring);
    std::rotate(teststring.begin(), teststring.begin() + 4, teststring.end());

    std::string numberstring; 
    for (const auto &c : teststring) {
        if (std::isdigit(c))
            numberstring += c;
        if (std::isupper(c))
            numberstring += std::to_string(static_cast<int>(c) - 55);
    }
    
    
    
    int segstart = 0;
    int step = 9;
    std::string prepended;
    long number = 0;
    while (segstart < numberstring.length() - step) {
        number = std::stol(prepended + numberstring.substr(segstart, step));
        int remainder = number % 97;
        prepended = std::to_string(remainder);
        if (remainder < 10)
            prepended = "0" + prepended;
        segstart = segstart + step;
        step = 7;
    }
    number = std::stol(prepended + numberstring.substr(segstart));
    return (number % 97 == 1);
}

void SayValidity(const std::string &iban) {
    std::cout << iban << (isValid(iban) ? " is " : " is not ") << "valid\n";
}

int main() {
    SayValidity("GB82 WEST 1234 5698 7654 32");
    SayValidity("GB82TEST12345698765432");
    return 0;
}









Fortran: program ibancheck

   use ISO_FORTRAN_ENV

   implicit none

   character(4), dimension(75) :: cc = (/ &
            "AD24","AE23","AL28","AT20","AZ28","BA20","BE16","BG22","BH22","BR29", &
            "BY28","CH21","CR22","CY28","CZ24","DE22","DK18","DO28","EE20","ES24", &
            "FI18","FO18","FR27","GB22","GE22","GI23","GL18","GR27","GT28","HR21", &
            "HU28","IE22","IL23","IQ23","IS26","IT27","JO30","KW30","KZ20","LB28", &
            "LC32","LI21","LT20","LU20","LV21","MC27","MD24","ME22","MK19","MR27", &
            "MT31","MU30","NL18","NO15","PK24","PL28","PS29","PT25","QA29","RO24", &
            "RS22","SA24","SC31","SE24","SI19","SK24","SM27","ST25","SV28","TL23", &
            "TN24","TR26","UA29","VG24","XK20" /)

    character(34), dimension(12) :: ibans = (/ "GB82 WEST 1234 5698 7654 32       ", &
                                               "GB82WEST12345698765432            ", & 
                                               "gb82 west 1234 5698 7654 32       ", &
                                               "GB82 TEST 1234 5698 7654 32       ", &
                                               "GR16 0110 1250 0000 0001 2300 695 ", &
                                               "GB29 NWBK 6016 1331 9268 19       ", &
                                               "SA03 8000 0000 6080 1016 7519     ", &
                                               "CH93 0076 2011 6238 5295 7        ", &
                                               "IL62 0108 0000 0009 9999 999      ", &
                                               "IL62-0108-0000-0009-9999-999      ", &
                                               "US12 3456 7890 0987 6543 210      ", &
                                               "GR16 0110 1250 0000 0001 2300 695X" /)

    integer :: i
    
    do i=1, size(ibans)
        if (checkIBAN(trim(ibans(i)))) then
            print *, "  valid IBAN: ", trim(ibans(i))
        else
            print *, "invalid IBAN: ", trim(ibans(i))
        end if
    end do

    return
 
contains

    function checkIBAN(ibancode) result(valid)
        character(len=*), intent(in) :: ibancode
        character(len=len(ibancode)) :: iban
        logical :: valid
        integer(int32) :: j, ascii, ibanSize 
        character(100) :: ibanRearrange, ibantoint
        character(2) :: temp
        valid = .false.

        iban = remove_blanks(ibancode)
        ibanSize = checkCountryCode(iban)
        if (ibanSize == len(trim(iban))) then
            ibanRearrange = iban(5:ibanSize)//iban(1:4)
            ibantoint = ""
            do j=1, ibanSize
                ascii = ichar(ibanRearrange(j:j))
                if ((ascii >= 65) .and. (ascii<=90)) then
                    write (temp,fmt='(I2)') ascii-55
                    ibantoint = trim(ibantoint) // temp
                else
                    ibantoint = trim(ibantoint) // ibanRearrange(j:j)
                end if 
            end do
            if (mod97(ibantoint) == 1) then
                valid = .true.
            end if
        end if
    end function checkIBAN
    
    function mod97(strint) result(res)
        character(len=*), intent(in) :: strint
        integer :: i, num, res
        res = 0
        do  i=1, len(trim(strint))
            read(strint(i:i),*) num
            res = mod((res*10 + num),97);
        end do
    end function mod97

    function checkCountryCode(iban) result(ibanlength)
        character(len=*), intent(in) :: iban
        integer(int16) :: ibanlength, i
        ibanlength = 0
        do i=1, size(cc)
            if (iban(1:2) == cc(i)(1:2)) then
                read(cc(i)(3:4),*) ibanlength
                exit
            end if
        end do
    end function checkCountryCode
 
    Recursive Function Stripper(string,ch) Result(stripped)
        Implicit None
        character(len=*), intent(in) :: string
        character, intent(in) :: ch
        character(:), allocatable :: stripped

        IF (LEN(string)==1) THEN
           IF (string==ch) THEN 
              stripped = ''
           ELSE
              stripped = string
           END IF
        ELSE
           IF (string(1:1)==ch) THEN
              stripped = stripper(string(2:),ch)
           ELSE
              stripped = string(1:1)//stripper(string(2:),ch)
           END IF
        END IF
    END Function stripper

    Function Remove_Blanks(string) Result(stripped)
        Implicit None
        character(len=*), intent(in) ::   string
        character(:), allocatable :: stripped

        stripped = trim(Stripper(trim(Stripper(string,' ')),achar(9)))
    END Function Remove_Blanks

end program ibancheck