IBAN Regex design [duplicate]
Asked Answered
O

4

26

Help me please to design Regex that will match all IBANs with all possible whitespaces. Because I've found that one, but it does not work with whitespaces.

[a-zA-Z]{2}[0-9]{2}[a-zA-Z0-9]{4}[0-9]{7}([a-zA-Z0-9]?){0,16}

I need at least that formats:

DE89 3704 0044 0532 0130 00
AT61 1904 3002 3457 3201
FR14 2004 1010 0505 0001 3
Os answered 20/6, 2017 at 14:45 Comment(6)
Did you try inserting zero-or-one whitespace at the desired places? Don't be afraid, the modified regex will not explode if you fiddle around a little.Romansh
FWIW, that doesn't validate an iban reliably. There's much more needed to do that.Contrasty
A good, extensive list that could be used is this one from Apache Commons. You can collect all the patterns that have been defined and adapt them to accept white spaces. For example: DE\d{2}\s*\d{4}\s*\d{4}\s*\d{4}\s*\d{4}\s*\d{2} will match your first example.Nankeen
To validate IBAN with all possible whitespaces, just remove the whitespaces before validating, makes things quite a bit simpler. But actually you just cannot fully validate by regex, as the main key for validation is the checksum.Maestoso
So, to validate an iban, I'd do: 1) normalize: convert to uppercase and remove anything but [A-Z0-9] 2) match pattern [A-Z]{2}[0-9]{2}[A-Z0-9]{1,30} 3) validate checksum. In addition, you can check the (country specific) length, but that is not needed in most use cases unless you want to rule out that someone had made up an IBAN by recalculating the checksum.Maestoso
I just wanted to know if there could be an IBAN, with empty spaces or "-" between ... and after reading a lot of complicated, not working regex, i did it my self. I thought i share it: /(?<![A-Z])[A-Z]{2}(\h|\-)?[0-9]{2}(\h|\-)?[A-Z0-9](?:(\h|\-)?[A-Z0-9]){10,29}(?![A-Z0-9])/Impregnable
B
64

Just to find the example IBAN's from those countries in a text :
Start with 2 letters then 2 digits.
Then allow a space before every 4 digits, optionally ending with 1 or 2 digits:

\b[A-Z]{2}[0-9]{2}(?:[ ]?[0-9]{4}){4}(?!(?:[ ]?[0-9]){3})(?:[ ]?[0-9]{1,2})?\b    

regex101 test here

Note that if the intention is to validate a complete string, that the regex can be simplified.
Since the negative look-ahead (?!...) won't be needed then.
And the word boundaries \b can be replaced by the start ^ and end $ of the line.

^[A-Z]{2}[0-9]{2}(?:[ ]?[0-9]{4}){4}(?:[ ]?[0-9]{1,2})?$

Also, it can be simplified even more if having the 4 groups of 4 connected digits doesn't really matter.

^[A-Z]{2}(?:[ ]?[0-9]){18,20}$

Extra

If you need to match an IBAN number from accross the world?
Then the BBAN part of the IBAN is allowed to have up to 30 numbers or uppercase letters. Reference
And can be written with either spaces or dashes or nothing in between.
For example: CC12-XXXX-12XX-1234-5678-9012-3456-7890-123

So the regex pattern to match a complete string with a long IBAN becomes a bit longer.

^([A-Z]{2}[ \-]?[0-9]{2})(?=(?:[ \-]?[A-Z0-9]){9,30}$)((?:[ \-]?[A-Z0-9]{3,5}){2,7})([ \-]?[A-Z0-9]{1,3})?$

regex101 test here

Also note, that a pure regex solution can't do calculations.
So to actually validate an IBAN number then extra code is required.

Example Javascript Snippet:

function smellsLikeIban(str){
 return /^([A-Z]{2}[ \-]?[0-9]{2})(?=(?:[ \-]?[A-Z0-9]){9,30}$)((?:[ \-]?[A-Z0-9]{3,5}){2,7})([ \-]?[A-Z0-9]{1,3})?$/.test(str);
}

function validateIbanChecksum(iban) {       
  const ibanStripped = iban.replace(/[^A-Z0-9]+/gi,'') //keep numbers and letters only
                           .toUpperCase(); //calculation expects upper-case
  const m = ibanStripped.match(/^([A-Z]{2})([0-9]{2})([A-Z0-9]{9,30})$/);
  if(!m) return false;
  
  const numbericed = (m[3] + m[1] + m[2]).replace(/[A-Z]/g,function(ch){
                        //replace upper-case characters by numbers 10 to 35
                        return (ch.charCodeAt(0)-55); 
                    });
  //The resulting number would be to long for javascript to handle without loosing precision.
  //So the trick is to chop the string up in smaller parts.
  const mod97 = numbericed.match(/\d{1,7}/g)
                          .reduce(function(total, curr){ return Number(total + curr)%97},'');

  return (mod97 === 1);
};

var arr = [
 'DE89 3704 0044 0532 0130 00', // ok
 'AT61 1904 3002 3457 3201', // ok
 'FR14 2004 1010 0505 0001 3', // wrong checksum
 'GB82-WEST-1234-5698-7654-32', // ok
 'NL20INGB0001234567', // ok
 'XX00 1234 5678 9012 3456 7890 1234 5678 90', // only smells ok
 'YY00123456789012345678901234567890', // only smells ok
 'NL20-ING-B0-00-12-34-567', // stinks, but still a valid checksum
 'XX22YYY1234567890123', // wrong checksum again
 '[email protected]' // This Is Not The IBAN You Are Looking For
];
arr.forEach(function (str) {
  console.log('['+ str +'] Smells Like IBAN:    '+ smellsLikeIban(str));
  console.log('['+ str +'] Valid IBAN Checksum: '+ validateIbanChecksum(str))
});
Bimetallic answered 20/6, 2017 at 15:31 Comment(12)
Where do you see the 4-character bank code in your regexes? Examples are NL20INGB0001234567 and GB82WEST12345698765432.Herta
@wind-rider The regexes were written to fit the formats the question asked for. Where some of the digits are grouped by 4. But indeed, the BBAN part of an IBAN can have up to 30 alphanumeric characters that are country-specific.Bimetallic
@wind-rider For completeness sake I've included a regex for other IBAN's.Bimetallic
@wind-rider After checking wikipedia and testing it against layouts from different countries I had to change the regex a bit. And included a regex101 test for it.Bimetallic
nice, I upvoted your answer :)Herta
@Bimetallic why the positive look-ahead in the "across the world" regex? your regex101 test still works without itBoley
@Vituel To assure that the BBAN part doesn't contain more than 30 letters or digits. See defenition for IBAN. If it were just to depend on the other groups then a BBAN with (5*6)+3 could still pass. Regex isn't only about what the pattern allows, but also what it doesn't allow.Bimetallic
first of all, thanks a lot for this. But according to Wikipedia only upper case letters are allowedTenner
@Tenner Good point. Hadn't spotted that yet on the Wikipedia page. It's been corrected. And if someone now still wants to allow lowercase letters also, they can just add the i flag to ignore case.Bimetallic
I noticed another issue, it correctly recognizes AB00111122223333444455556666777788 but not AB00 1111 2222 3333 4444 5555 6666 7777 88. There is probably an issue with the spaces and the maximum length.Tenner
@Tenner Thanks for testing it that thoroughly! Indeed, the {2,6} had to be changed to {2,7}. It wasn't a problem for the one without spaces because it then matches groups per 5 digits. But for one with spaces, 6*4=24 had to be 7*4=28. It has been updated. (Btw, this is an old answer of mine, and I was kinda surprised some people somehow find it in the long list of SO questions)Bimetallic
A "smellsLikeIBAN" without limiting it to start and end of line: /(?<![A-Z])[A-Z]{2}(\h|\-)?[0-9]{2}(\h|\-)?[A-Z0-9](?:(\h|\-)?[A-Z0-9]){10,29}(?![A-Z0-9])/. Successfully tested with @Bimetallic last test regex101.com/r/dzDqmM/56 (turn on g (global))Impregnable
G
6

Here is a suggestion that may works for the patterns you provided:

[A-Z]{2}\d{2} ?\d{4} ?\d{4} ?\d{4} ?\d{4} ?[\d]{0,2}

Try it on regex101


Explanation

  • [A-Z]{2}\d{2} ? 2 capital letters followed by 2 digits (optional space)
  • \d{4} ? 4 digits, repeated 4 times (optional space)
  • [\d]{0,2} 0 to 2 digits
Girgenti answered 20/6, 2017 at 14:56 Comment(1)
This won't allow letters after the beginning. His existing pattern allows this.Domesday
A
2

You can use a regex like this:

^[A-Z]{2}\d{2} (?:\d{4} ){3}\d{4}(?: \d\d?)?$

Working demo

This will match only those string formats

Athalie answered 20/6, 2017 at 14:54 Comment(2)
Thank you but this doesn't works if you delete spaces. What I meant I can't understand how to handle any whitespaces positions (including no whitespaces).Os
@Maximus, regular expression helps you match patterns, if you need to match arbitrary characters, then you will have to use a whitespace check all the time, for instance: [A-Z]\s*[A-Z]\s*\d\s*\d\s*.....etc. Your question is not clear, you should update it and add more description with more sample as well. However, if my answer answers your question and you just want to make spaces optional, you need just to append ? to each blank spaceAthalie
D
1

It's probably best to look up the specifications for a correct IBAN number. But if you want to have a regex similar to your existing one, but with spaces, you can use the following one:

^[a-zA-Z]{2}[0-9]{2}\s?[a-zA-Z0-9]{4}\s?[0-9]{4}\s?[0-9]{3}([a-zA-Z0-9]\s?[a-zA-Z0-9]{0,4}\s?[a-zA-Z0-9]{0,4}\s?[a-zA-Z0-9]{0,4}\s?[a-zA-Z0-9]{0,3})?$

Here is a live example: https://regex101.com/r/ZyIPLD/1

Domesday answered 20/6, 2017 at 14:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.