IBAN正则表达式设计

25

请帮我设计一个正则表达式,可以匹配所有可能包含空格的IBAN。我找到了一个正则表达式,但它不能匹配包含空格的IBAN。

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

我至少需要这些格式:

DE89 3704 0044 0532 0130 00
AT61 1904 3002 3457 3201
FR14 2004 1010 0505 0001 3

2
你试过在所需位置插入零或一空格吗?别害怕,如果你动手尝试一下,修改后的正则表达式不会出错。 - Filburt
就此而言,那并不能可靠地验证IBAN。还需要做更多的工作。 - baao
一个好的、广泛的列表可以使用Apache Commons中的这个。您可以收集所有已定义的模式,并将它们调整为接受空格。例如:DE\d{2}\s*\d{4}\s*\d{4}\s*\d{4}\s*\d{4}\s*\d{2}将匹配您的第一个示例。 - Hannon Queiroz
1
为了验证带有所有可能空格的IBAN,只需在验证之前删除空格,这样会使事情变得简单得多。但实际上,您无法仅通过正则表达式完全验证,因为验证的主要关键是校验和。 - A.P.
1
因此,要验证IBAN,我会执行以下操作: 1)标准化:转换为大写并删除除“[A-Z0-9]”之外的任何内容 2)匹配模式“[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}” 3)验证校验和。此外,您可以检查(特定于国家/地区的)长度,但在大多数用例中不需要,除非您想排除某人通过重新计算校验和来捏造IBAN。 - A.P.
我只是想知道是否可能有一个带有空格或“-”的IBAN......在阅读了很多复杂的、不起作用的正则表达式之后,我自己做了一下。我想分享一下:/(?<![A-Z])[A-Z]{2}(\h|\-)?[0-9]{2}(\h|\-)?[A-Z0-9](?:(\h|\-)?[A-Z0-9]){10,29}(?![A-Z0-9])/ - cottton
4个回答

61

只需在文本中查找这些国家的示例IBAN:
首先是2个字母,然后是2位数字。
然后在每4个数字之前允许一个空格,可选择以1或2个数字结尾:

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

在这里进行regex101测试

请注意,如果意图是验证完整的字符串,则可以简化regex。
因为不需要使用否定的look-ahead (?!...)
单词边界\b可以替换为行的开头^和结尾$

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

此外,如果四个四个连接的数字组并不重要,那么它甚至可以更加简化。

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

额外信息

如果您需要匹配来自世界各地的IBAN号码?
那么IBAN的BBAN部分允许最多有30个数字或大写字母。参考
并且可以用空格、破折号或无分隔符的方式书写。
例如:CC12-XXXX-12XX-1234-5678-9012-3456-7890-123

因此,用于匹配包含长IBAN的完整字符串的正则表达式模式会变得有点长。

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

在这里进行regex101测试

还要注意,纯正则表达式解决方案无法进行计算。
因此,需要额外的代码才能实际验证IBAN号码。

Javascript示例代码:

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
 'droid@i.ban' // 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))
});


1
@wind-rider 这些正则表达式是为了适应问题所要求的格式而编写的,其中一些数字被分组为4个。但实际上,IBAN的BBAN部分可以具有最多30个特定于国家/地区的字母数字字符。 - LukStorms
1
@wind-rider 为了完整起见,我已经包含了其他IBAN的正则表达式。 - LukStorms
1
@wind-rider 在查看维基百科并测试不同国家的布局后,我不得不稍微更改正则表达式。并且为此包括了一个 regex101 测试。 - LukStorms
1
@Vituel 为确保BBAN部分不超过30个字母或数字,请参阅IBAN的定义。如果仅依赖其他组,则具有(5*6)+3的BBAN仍可通过。正则表达式不仅关乎模式允许的内容,还关乎它不允许的内容。 - LukStorms
@Naryoril 很好的观点。我还没有在维基百科页面上发现这一点。已经进行了更正。如果现在有人仍然想允许小写字母,他们只需添加i标志以忽略大小写即可。 - LukStorms
显示剩余7条评论

6
这里有一个建议,可能适用于您提供的模式:
[A-Z]{2}\d{2} ?\d{4} ?\d{4} ?\d{4} ?\d{4} ?[\d]{0,2}

在 regex101 上试一试


解释

  • [A-Z]{2}\d{2} ?:2个大写字母后跟2个数字(可选空格)
  • \d{4} ?:4个数字,重复4次(可选空格)
  • [\d]{0,2}:0至2个数字

这将不允许在开头之后输入字母。他现有的模式允许这样做。 - ssc-hrep3

2
您可以使用类似以下的正则表达式:
^[A-Z]{2}\d{2} (?:\d{4} ){3}\d{4}(?: \d\d?)?$

演示链接

这将只匹配那些字符串格式。


谢谢,但是如果删除空格,这个方法就不起作用了。我的意思是我不知道如何处理任何空格位置(包括没有空格的情况)。 - Maximus
@Maximus,正则表达式可以帮助你匹配模式。如果你需要匹配任意字符,那么你就必须一直使用空格检查,例如:[A-Z]\s*[A-Z]\s*\d\s*\d\s*.....等等。你的问题不太清楚,你应该更新它并添加更多的描述和示例。然而,如果我的答案回答了你的问题,并且你只想让空格变成可选的,你只需要在每个空格后面加上 ?` 即可。 - Federico Piazza

1

最好查找正确的IBAN号码规范。但是,如果您想要一个类似于现有正则表达式但带有空格的正则表达式,可以使用以下正则表达式:

^[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})?$

这里有一个实时示例:https://regex101.com/r/ZyIPLD/1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接