RegEx用于匹配英国邮政编码

问题描述 投票:157回答:29

我正在使用正则表达式,它将仅在输入字符串中验证完整复杂的英国邮政编码。所有不常见的邮政编码表格都必须与通常一样。例如:

火柴

  • 肘故事
  • SE5 0EG
  • SE50EG
  • se5 0eg
  • WC2H 7LT

没有比赛

  • 围巾溶解了
  • 围巾溶解了
  • WC2H

我该如何解决这个问题?

regex validation postal-code
29个回答
180
投票

我建议你看看英国政府数据标准的邮政编码[现已链接死亡; archive of XML,请参阅Wikipedia进行讨论]。有关于数据的简要描述,附加的xml架构提供了正则表达式。它可能不是你想要的,但它将是一个很好的起点。 RegEx略微不同于XML,因为给定定义允许A9A 9AA格式的第三位P字符。

英国政府提供的RegEx是:

([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9][A-Za-z]?))))\s?[0-9][A-Za-z]{2})

正如维基百科的讨论所指出的那样,这将允许一些非真实的邮政编码(例如那些以AA,ZY开头)并且它们确实提供了您可以尝试的更严格的测试。


10
投票

这是Google在其i18napis.appspot.com域上提供的正则表达式:

GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|BX|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}

10
投票

邮政编码可能会发生变化,验证邮政编码的唯一真实方法是获得完整的邮政编码列表,看看它是否存在。

但正则表达式很有用,因为它们:

  • 易于使用和实施
  • 很短
  • 快跑了
  • 很容易维护(与完整的邮政编码列表相比)
  • 仍然捕获大多数输入错误

但正则表达式往往难以维护,特别是对于那些一开始没有提出它的人。所以一定是:

  • 尽可能容易理解
  • 相对未来的证据

这意味着这个答案中的大多数正则表达式都不够好。例如。我可以看到[A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y]将匹配AA1A形式的邮政编码区域 - 但是如果添加新的邮政编码区域,那将是一个痛苦的问题,因为很难理解它匹配的邮政编码区域。

我还希望我的正则表达式将邮政编码的前半部分和后半部分匹配为括号匹配。

所以我想出了这个:

(GIR(?=\s*0AA)|(?:[BEGLMNSW]|[A-Z]{2})[0-9](?:[0-9]|(?<=N1|E1|SE1|SW1|W1|NW1|EC[0-9]|WC[0-9])[A-HJ-NP-Z])?)\s*([0-9][ABD-HJLNP-UW-Z]{2})

在PCRE格式中,它可以写成如下:

/^
  ( GIR(?=\s*0AA) # Match the special postcode "GIR 0AA"
    |
    (?:
      [BEGLMNSW] | # There are 8 single-letter postcode areas
      [A-Z]{2}     # All other postcode areas have two letters
      )
    [0-9] # There is always at least one number after the postcode area
    (?:
      [0-9] # And an optional extra number
      |
      # Only certain postcode areas can have an extra letter after the number
      (?<=N1|E1|SE1|SW1|W1|NW1|EC[0-9]|WC[0-9])
      [A-HJ-NP-Z] # Possible letters here may change, but [IO] will never be used
      )?
    )
  \s*
  ([0-9][ABD-HJLNP-UW-Z]{2}) # The last two letters cannot be [CIKMOV]
$/x

对我来说,这是在尽可能多的验证之间取得适当的平衡,同时适应未来的需求并且易于维护。


9
投票

我一直在寻找最后一天左右的英国邮政编码正则表达式,并偶然发现了这个帖子。我按照上面的大部分建议进行了工作,但没有一个对我有用,所以我提出了自己的正则表达式,据我所知,截至2013年1月,所有有效的英国邮政编码都是根据皇家邮政)。

正则表达式和一些简单的邮政编码检查PHP代码发布如下。注意: - 它允许使用较低或大写的邮政编码和GIR 0AA异常,但是为了处理输入的邮政编码中间空间的存在,它还使用简单的str_replace来删除测试前的空间反对正则表达式。任何超出此范围的差异和皇家邮政本身甚至在他们的文献中都没有提到它们(参见http://www.royalmail.com/sites/default/files/docs/pdf/programmers_guide_edition_7_v5.pdf并从第17页开始阅读)!

注意:在皇家邮政自己的文献(上面的链接)中,如果这些字符是字母,则第3和第4个位置存在轻微的歧义,并且存在例外情况。我直接联系了皇家邮政,并用他们自己的话说明了“Award NAA格式的外向代码第4位的信件没有例外,第3个位置例外仅适用于”外展代码“的最后一个字母。格式ANA NAA。“直接从马的嘴里出来!

<?php

    $postcoderegex = '/^([g][i][r][0][a][a])$|^((([a-pr-uwyz]{1}([0]|[1-9]\d?))|([a-pr-uwyz]{1}[a-hk-y]{1}([0]|[1-9]\d?))|([a-pr-uwyz]{1}[1-9][a-hjkps-uw]{1})|([a-pr-uwyz]{1}[a-hk-y]{1}[1-9][a-z]{1}))(\d[abd-hjlnp-uw-z]{2})?)$/i';

    $postcode2check = str_replace(' ','',$postcode2check);

    if (preg_match($postcoderegex, $postcode2check)) {

        echo "$postcode2check is a valid postcode<br>";

    } else {

        echo "$postcode2check is not a valid postcode<br>";

    }

?>

我希望它可以帮助遇到此线程的其他任何人寻找解决方案。


7
投票

这是一个基于文档中指定的格式的正则表达式,它与marcj的答案相关联:

/^[A-Z]{1,2}[0-9][0-9A-Z]? ?[0-9][A-Z]{2}$/

该规格与规格之间的唯一区别在于,根据规格,最后2个字符不能在[CIKMOV]中。

编辑:这是另一个测试尾随字符限制的版本。

/^[A-Z]{1,2}[0-9][0-9A-Z]? ?[0-9][A-BD-HJLNP-UW-Z]{2}$/

5
投票

上面的一些正则表达式有点限制。注意真正的邮政编码:“W1K 7AA”将失败,因为上面的规则“位置3 - 仅使用AEHMNPRTVXY”,因为“K”将被禁止。

正则表达式:

^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKPS-UW])[0-9][ABD-HJLNP-UW-Z]{2})$

似乎更准确一点,请参阅Wikipedia article entitled 'Postcodes in the United Kingdom'

请注意,此正则表达式只需要大写字符。

更大的问题是,您是否限制用户输入以仅允许实际存在的邮政编码,或者您是否只是试图阻止用户在表单字段中输入完整的垃圾。正确匹配每个可能的邮政编码,以及将来证明它,是一个更难的难题,除非你是HMRC,否则可能不值得。


4
投票

基本规则:

^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABD-HJLNP-UW-Z]{2}$

英国的邮政编码(或称为邮政编码)由五到七个由空格分隔的字母数字字符组成。涵盖哪些角色可以出现在特定位置的规则相当复杂,并且充满了例外情况。因此,刚才显示的正则表达式遵循基本规则。

完整规则:

如果您需要一个以可读性为代价来勾选邮政编码规则的所有方框的正则表达式,请转到:

^(?:(?:[A-PR-UWYZ][0-9]{1,2}|[A-PR-UWYZ][A-HK-Y][0-9]{1,2}|[A-PR-UWYZ][0-9][A-HJKSTUW]|[A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y]) [0-9][ABD-HJLNP-UW-Z]{2}|GIR 0AA)$

资料来源:https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s16.html

对我们的客户数据库进行测试,看起来非常准确。


4
投票

我使用以下正则表达式,我测试了所有有效的英国邮政编码。它基于推荐的规则,但是尽可能合理地压缩,并且不使用任何特殊语言特定的正则表达规则。

([A-PR-UWYZ]([A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y])?|[0-9]([0-9]|[A-HJKPSTUW])?) ?[0-9][ABD-HJLNP-UW-Z]{2})

它假定邮政编码已转换为大写并且没有前导或尾随字符,但会接受outcode和incode之间的可选空格。

特殊的“GIR0 0AA”邮政编码被排除在外,不会验证,因为它不在邮政编码的官方邮局列表中,据我所知,不会被用作注册地址。如果需要,添加它应该是一个特殊情况。


3
投票

邮政编码的前半部分有效格式

  • [A-Z] [A-Z] [0-9] [A-Z]
  • [A-Z] [A-Z] [0-9] [0-9]
  • [A-Z] [0-9] [0-9]
  • [A-Z] [A-Z] [0-9]
  • [A-Z] [A-Z] [A-Z]
  • [A-Z] [0-9] [A-Z]
  • [A-Z] [0-9]

例外 位置1 - 未使用QVX 位置2 - 除GIR 0AA外未使用IJZ 位置3 - 仅使用AEHMNPRTVXY 第4位 - ABEHMNPRVWXY

邮编的下半部分

  • [0-9] [A-Z] [A-Z]

例外 位置2 + 3 - 未使用CIKMOV

请记住,并非使用所有可能的代码,因此该列表对于有效代码是必要但不充分的条件。可能更容易匹配所有有效代码的列表?


3
投票

以下是我们处理英国邮政编码问题的方法:

^([A-Za-z]{1,2}[0-9]{1,2}[A-Za-z]?[ ]?)([0-9]{1}[A-Za-z]{2})$

说明:

  • 期望1或2个a-z字符,上限或下限
  • 期待1或2个数字
  • 期望0或1个a-z字符,上限或下限
  • 允许可选空间
  • 期待1个号码
  • 期望2 a-z,上限或下限罚款

这得到大多数格式,然后我们使用db来验证邮政编码是否真实,这个数据是由openpoint https://www.ordnancesurvey.co.uk/opendatadownload/products.html驱动的

希望这可以帮助


3
投票

根据皇家邮政的programmer's guide检查邮政编码的有效格式:

          |----------------------------outward code------------------------------| |------inward code-----|
#special↓       α1        α2    AAN  AANA      AANN      AN    ANN    ANA (α3)        N         AA
^(GIR 0AA|[A-PR-UWYZ]([A-HK-Y]([0-9][A-Z]?|[1-9][0-9])|[1-9]([0-9]|[A-HJKPSTUW])?) [0-9][ABD-HJLNP-UW-Z]{2})$

doogal.co.uk上的所有邮政编码都匹配,除了那些不再使用的邮政编码。

在空格后添加?并使用不区分大小写的匹配来回答此问题:

'se50eg'.match(/^(GIR 0AA|[A-PR-UWYZ]([A-HK-Y]([0-9][A-Z]?|[1-9][0-9])|[1-9]([0-9]|[A-HJKPSTUW])?) ?[0-9][ABD-HJLNP-UW-Z]{2})$/ig);
Array [ "se50eg" ]

81
投票

看起来我们将要使用^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$,这是Minglis上面的一个略微修改过的版本。

但是,我们将不得不仔细调查规则是什么,因为上面列出的各种解决方案似乎对允许哪些字母应用不同的规则。

经过一番研究,我们发现了更多信息。显然,'govtalk.gov.uk'上的一个页面指向邮政编码规范govtalk-postcodes。这指向XML Schema上的XML模式,它提供了邮政编码规则的“伪正则表达式”语句。

我们已经采取了这个并且稍微努力了一下,给我们以下表达式:

^((GIR &0AA)|((([A-PR-UWYZ][A-HK-Y]?[0-9][0-9]?)|(([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y]))) &[0-9][ABD-HJLNP-UW-Z]{2}))$

这使空格可选,但确实将您限制为一个空格(将'&'替换为'{0,}表示无限空格)。它假定所有文本必须是大写的。

如果您想允许小写,任意数量的空格,请使用:

^(([gG][iI][rR] {0,}0[aA]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y]))) {0,}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2}))$

这不包括海外领土,只强制执行格式,而不是存在不同的区域。它基于以下规则:

可以接受以下格式:

  • “GIVES 0AA”
  • 啊,自我
  • 我剪了丝绸
  • 吸收丝绸
  • 我吐丝
  • 生病的丝绸
  • 更细的丝绸

哪里:

  • 9可以是任何单个数字。
  • A可以是除Q,V或X之外的任何字母。
  • B可以是除I,J或Z之外的任何字母。
  • C可以是除I,L,M,N,O,P,Q,R,V,X,Y或Z之外的任何字母。
  • D可以是除I,J或Z之外的任何字母。
  • E可以是A,B,E,H,M,N,P,R,V,W,X或Y中的任何一种。
  • Z可以是除C,I,K,M,O或V之外的任何字母。

最好的祝愿

科林


3
投票

这个允许来自两侧的空白空间和制表符,以防您不希望验证失败,然后修剪它的服务器端。

^\s*(([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) {0,1}[0-9][A-Za-z]{2})\s*$)

3
投票

我想要一个简单的正则表达式,允许太多,但不要拒绝有效的邮政编码。我去了(输入是一个剥离/修剪的字符串):

/^([a-z0-9]\s*){5,7}$/i

长度5到7(不计空白)意味着我们允许最短的邮政编码,如“L1 8JQ”以及最长的邮编,如“OL14 5ET”。

编辑:将8更改为7,因此我们不允许8个字符的邮政编码。


2
投票

要添加到此列表,我使用的更实用的正则表达式允许用户输入empty string是:

^$|^(([gG][iI][rR] {0,}0[aA]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y]))) {0,1}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2}))$

此正则表达式允许大写和小写字母之间有可选空格

从软件开发人员的角度来看,这个正则表达式对于地址可选的软件非常有用。例如,如果用户不想提供他们的地址详细信息


1
投票

看看这个页面上的python代码:

http://www.brunningonline.net/simon/blog/archives/001292.html

我有一些邮政编码解析要做。要求非常简单;我必须将邮政编码解析为outcode和(可选)incode。好消息是我不需要进行任何验证 - 我只需要以模糊的方式切断我提供的内容。在格式化方面,我无法假设我的导入,即大小写和嵌入空格。但这不是坏消息;坏消息是我必须在RPG中全部完成。 :-(

不过,我把一些Python函数放在一起,以澄清我的想法。

我用它来为我处理邮政编码。


1
投票

我们得到了一个规范:

UK postcodes must be in one of the following forms (with one exception, see below): 
    § A9 9AA 
    § A99 9AA
    § AA9 9AA
    § AA99 9AA
    § A9A 9AA
    § AA9A 9AA
where A represents an alphabetic character and 9 represents a numeric character.
Additional rules apply to alphabetic characters, as follows:
    § The character in position 1 may not be Q, V or X
    § The character in position 2 may not be I, J or Z
    § The character in position 3 may not be I, L, M, N, O, P, Q, R, V, X, Y or Z
    § The character in position 4 may not be C, D, F, G, I, J, K, L, O, Q, S, T, U or Z
    § The characters in the rightmost two positions may not be C, I, K, M, O or V
The one exception that does not follow these general rules is the postcode "GIR 0AA", which is a special valid postcode.

我们想出了这个:

/^([A-PR-UWYZ][A-HK-Y0-9](?:[A-HJKS-UW0-9][ABEHMNPRV-Y0-9]?)?\s*[0-9][ABD-HJLNP-UW-Z]{2}|GIR\s*0AA)$/i

但请注意 - 这允许组之间的任意数量的空格。


1
投票

我有英国邮政编码验证的正则表达式。

这适用于内部或外部的所有类型的邮政编码

^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))) || ^((GIR)[ ]?(0AA))$|^(([A-PR-UWYZ][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][0-9][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][A-HK-Y0-9][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][A-HK-Y0-9][0-9][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][0-9][A-HJKS-UW0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][A-HK-Y0-9][0-9][ABEHMNPRVWXY0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$

这适用于所有类型的格式。

例:

AB10 -------------------->只有外面的POSTCODE

A1 1AA ------------------>(外部和内部)POSTCODE的组合

WC2A --------------------> OUTER


1
投票

接受的答案反映了皇家邮政的规则,尽管正则表达中存在拼写错误。这个错字似乎也出现在gov.uk网站上(就像在XML存档页面中一样)。

在格式A9A 9AA中,规则允许P字符在第三个位置,而正则表达式不允许这个。正确的正则表达式是:

(GIR 0AA)|((([A-Z-[QVX]][0-9][0-9]?)|(([A-Z-[QVX]][A-Z-[IJZ]][0-9][0-9]?)|(([A-Z-[QVX]][0-9][A-HJKPSTUW])|([A-Z-[QVX]][A-Z-[IJZ]][0-9][ABEHMNPRVWXY])))) [0-9][A-Z-[CIKMOV]]{2}) 

缩短这会产生以下正则表达式(使用Perl / Ruby语法):

(GIR 0AA)|([A-PR-UWYZ](([0-9]([0-9A-HJKPSTUW])?)|([A-HK-Y][0-9]([0-9ABEHMNPRVWXY])?))\s?[0-9][ABD-HJLNP-UW-Z]{2})

它还包括第一和第二块之间的可选空间。


1
投票

我在几乎所有的变化和大规模转移pdf中的正则表达式以及维基百科网站上的内容是这样的,特别是对于维基百科正则表达式,在第一个|(垂直条)之后需要有^。我通过测试AA9A 9AA来解决这个问题,因为否则A9A 9AA的格式检查将验证它。例如,检查EC1D 1BB应该是无效的,因为C1D 1BB是有效格式,因此返回有效。

这是我为一个好的正则表达式想出来的:

^([G][I][R] 0[A]{2})|^((([A-Z-[QVX]][0-9]{1,2})|([A-Z-[QVX]][A-HK-Y][0-9]{1,2})|([A-Z-[QVX]][0-9][ABCDEFGHJKPSTUW])|([A-Z-[QVX]][A-HK-Y][0-9][ABEHMNPRVWXY])) [0-9][A-Z-[CIKMOV]]{2})$

0
投票

我需要一个可以在SAS中使用PRXMATCH和相关功能的版本,所以我想出了这个:

^[A-PR-UWYZ](([A-HK-Y]?\d\d?)|(\d[A-HJKPSTUW])|([A-HK-Y]\d[ABEHMNPRV-Y]))\s?\d[ABD-HJLNP-UW-Z]{2}$

测试用例和说明:

/* 
Notes
The letters QVX are not used in the 1st position.
The letters IJZ are not used in the second position.
The only letters to appear in the third position are ABCDEFGHJKPSTUW when the structure starts with A9A.
The only letters to appear in the fourth position are ABEHMNPRVWXY when the structure starts with AA9A.
The final two letters do not use the letters CIKMOV, so as not to resemble digits or each other when hand-written.
*/

/*
    Bits and pieces
    1st position (any):         [A-PR-UWYZ]         
    2nd position (if letter):   [A-HK-Y]
    3rd position (A1A format):  [A-HJKPSTUW]
    4th position (AA1A format): [ABEHMNPRV-Y]
    Last 2 positions:           [ABD-HJLNP-UW-Z]    
*/


data example;
infile cards truncover;
input valid 1. postcode &$10. Notes &$100.;
flag = prxmatch('/^[A-PR-UWYZ](([A-HK-Y]?\d\d?)|(\d[A-HJKPSTUW])|([A-HK-Y]\d[ABEHMNPRV-Y]))\s?\d[ABD-HJLNP-UW-Z]{2}$/',strip(postcode));
cards;
1  EC1A 1BB  Special case 1
1  W1A 0AX   Special case 2
1  M1 1AE    Standard format
1  B33 8TH   Standard format
1  CR2 6XH   Standard format
1  DN55 1PT  Standard format
0  QN55 1PT  Bad letter in 1st position
0  DI55 1PT  Bad letter in 2nd position
0  W1Z 0AX   Bad letter in 3rd position
0  EC1Z 1BB  Bad letter in 4th position
0  DN55 1CT  Bad letter in 2nd group
0  A11A 1AA  Invalid digits in 1st group
0  AA11A 1AA  1st group too long
0  AA11 1AAA  2nd group too long
0  AA11 1AAA  2nd group too long
0  AAA 1AA   No digit in 1st group
0  AA 1AA    No digit in 1st group
0  A 1AA     No digit in 1st group
0  1A 1AA    Missing letter in 1st group
0  1 1AA     Missing letter in 1st group
0  11 1AA    Missing letter in 1st group
0  AA1 1A    Missing letter in 2nd group
0  AA1 1     Missing letter in 2nd group
;
run;

0
投票

下面的方法将检查邮政编码并提供完整的信息

const valid_postcode = postcode => {
    try {
        postcode = postcode.replace(/\s/g, "");
        const fromat = postcode
            .toUpperCase()
            .match(/^([A-Z]{1,2}\d{1,2}[A-Z]?)\s*(\d[A-Z]{2})$/);
        const finalValue = `${fromat[1]} ${fromat[2]}`;
        const regex = /^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$/i;
        return {
            isValid: regex.test(postcode),
            formatedPostCode: finalValue,
            error: false,
            info: 'It is a valid postcode'
        };
    } catch (error) {
        return { error: true , info: 'Invalid post code has been entered!'};
    }
};
valid_postcode('GU348RR')
result => {isValid: true, formatedPostCode: "GU34 8RR", error: false, info: "It is a valid postcode"}
valid_postcode('sdasd4746asd')
result => {error: true, info: "Invalid post code has been entered!"}
valid_postcode('787898523')
result => {error: true, info: "Invalid post code has been entered!"}

42
投票

没有能够验证邮政编码的全面的英国邮政编码正则表达式。您可以使用正则表达式检查邮政编码是否格式正确;并不是说它确实存在。

邮政编码是任意复杂的,不断变化的。例如,对于每个邮政编码区域,outcode W1不会,也可能永远不会有1到99之间的每个数字。

你不能指望目前永远存在的是什么。例如,在1990年,邮局决定阿伯丁变得有点拥挤。他们在AB1-5的末尾添加了一个0,使其成为AB10-50,然后在这些之间创建了许多邮政编码。

无论何时构建新街道,都会创建新的邮政编码。这是获得构建许可的过程的一部分;地方当局有义务与邮局保持最新情况(并非他们都这样做)。

此外,正如许多其他用户所指出的那样,有特殊的邮政编码,如Girobank,GIR 0AA,以及圣诞老人信件,SAN TA1 - 你可能不想在那里发布任何东西,但它似乎没有被任何其他答案覆盖。

然后,有BFPO邮政编码,现在是changing to a more standard format。两种格式都有效。最后,还有海外领土source Wikipedia

+----------+----------------------------------------------+
| Postcode |                   Location                   |
+----------+----------------------------------------------+
| AI-2640  | Anguilla                                     |
| ASCN 1ZZ | Ascension Island                             |
| STHL 1ZZ | Saint Helena                                 |
| TDCU 1ZZ | Tristan da Cunha                             |
| BBND 1ZZ | British Indian Ocean Territory               |
| BIQQ 1ZZ | British Antarctic Territory                  |
| FIQQ 1ZZ | Falkland Islands                             |
| GX11 1AA | Gibraltar                                    |
| PCRN 1ZZ | Pitcairn Islands                             |
| SIQQ 1ZZ | South Georgia and the South Sandwich Islands |
| TKCA 1ZZ | Turks and Caicos Islands                     |
+----------+----------------------------------------------+

接下来,您必须考虑到英国将其邮政编码系统“导出”到世界上许多地方。验证“英国”邮政编码的任何内容也将验证许多其他国家/地区的邮政编码。

如果您想验证英国邮政编码,最安全的方法是使用当前邮政编码的查找。有很多选择:

  • Ordnance Survey根据开放数据许可证发布Code-Point Open。它将落后于时代,但它是免费的。这将(可能 - 我不记得)不包括北爱尔兰的数据,因为军械测量局没有在那里进行调查。北爱尔兰的地图由北爱尔兰的军械测量局进行,他们有单独的,付费的Pointer产品。您可以使用此功能并附加少量未轻易覆盖的内容。
  • 皇家邮政发布了Postcode Address File (PAF),其中包括我不确定Code-Point Open的BFPO。它定期更新,但需要花钱(有时它们可​​能是彻头彻尾的意思)。 PAF包括完整的地址而不仅仅是邮政编码,并附带自己的Programmers Guide。开放数据用户组(ODUG)目前正在游说让PAF免费发布,here's a description of their position
  • 最后,有AddressBase。这是Ordnance Survey,地方当局,皇家邮政和匹配公司之间的合作,以创建关于所有英国地址的所有信息的权威目录(它们也相当成功)。这是付费的,但如果您与地方当局,政府部门或政府服务部门合作,他们可以免费使用。除了包含的邮政编码之外,还有更多的信息。

0
投票

我从XML文档中偷了这个,它似乎涵盖了没有硬编码GIRO的所有情况:

%r{[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][A-Z]{2}}i

(使用ignore case的Ruby语法)


35
投票

我最近发布了an answerthis question on UK postcodes for the R language。我发现英国政府的正则表达式模式不正确,无法正确验证某些邮政编码。不幸的是,这里的许多答案都是基于这种不正确的模式。

我将在下面概述其中一些问题,并提供一个实际有效的修订正则表达式。


Note

我的答案(和一般的正则表达式):

  • 仅验证邮政编码格式。
  • 不确保邮政编码合法存在。 为此,请使用适当的API!有关更多信息,请参阅Ben's answer

如果您不关心坏的正则表达式并且只想跳到答案,请向下滚动到“答案”部分。

The Bad Regex

不应使用本节中的正则表达式。

这是英国政府为开发人员提供的失败的正则表达式(不确定这个链接将会持续多长时间,但你可以在他们的Bulk Data Transfer documentation中看到它):

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$

问题

Problem 1 - Copy/Paste

See regex in use here

正如许多开发人员可能做的那样,他们复制/粘贴代码(特别是正则表达式)并粘贴它们以期望它们起作用。虽然这在理论上很好,但在这种特殊情况下却失败了,因为从这个文档中复制/粘贴实际上将一个字符(空格)更改为换行符,如下所示:

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))
[0-9][A-Za-z]{2})$

大多数开发人员要做的第一件事就是在不考虑两次的情况下擦除换行符。现在正则表达式将不匹配其中带有空格的邮政编码(除了GIR 0AA邮政编码)。

要解决此问题,应使用空格字符替换换行符:

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$
                                                                                                                                                     ^

Problem 2 - Boundaries

See regex in use here

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$
^^                     ^ ^                                                                                                                                            ^^

邮政编码正则表达式不正确地锚定了正则表达式。如果像fooA11 1AA这样的值通过,那么使用这个正则表达式验证邮政编码的任何人都会感到惊讶。那是因为他们已经锚定了第一个选项的开始和第二个选项的结束(彼此独立),正如上面的正则表达式所指出的那样。

这意味着^(在行的开头断言位置)仅适用于第一个选项([Gg][Ii][Rr] 0[Aa]{2}),因此第二个选项将验证以邮政编码结尾的任何字符串(无论之前是什么)。

类似地,第一个选项没有锚定到行$的末尾,因此GIR 0AAfoo也被接受。

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$

要解决此问题,应将这两个选项包装在另一个组(或非捕获组)中,并将锚点放在其周围:

^(([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2}))$
^^                                                                                                                                                                      ^^

Problem 3 - Improper Character Set

See regex in use here

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$
                                                                                       ^^

正则表达式在这里缺少一个-来表示一系列字符。就目前而言,如果邮政编码的格式为ANA NAA(其中A代表一个字母而N代表一个数字),并且它以AZ以外的任何东西开头,它将失败。

这意味着它将匹配A1A 1AAZ1A 1AA,但不匹配B1A 1AA

要解决此问题,字符-应放在相应字符集中的AZ之间:

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$
                                                                                        ^

Problem 4 - Wrong Optional Character Set

See regex in use here

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$
                                                                                                                                        ^

我发誓他们甚至在网上公布之前都没有测试过这个东西。他们使错误的字符集可选。他们在选项2(第9组)的第四个子选项中选择了[0-9]选项。这允许正则表达式匹配格式错误的邮政编码,如AAA 1AA

要解决此问题,请将下一个字符类设置为可选(然后使设置的[0-9]匹配一次):

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9][A-Za-z]?)))) [0-9][A-Za-z]{2})$
                                                                                                                                                ^

Problem 5 - Performance

这个正则表达式的表现极差。首先,他们放置了最不可能的模式选项,以便在开始时匹配GIR 0AA。与任何其他邮政编码相比,有多少用户可能拥有此邮政编码;可能从未?这意味着每次使用正则表达式时,它必须首先耗尽此选项,然后再继续下一个选项。要了解性能如何受到影响,请检查original regexsame regex after having flipped the options采取的步数(35)(22)。

性能的第二个问题是由于整个正则表达式的结构方式。如果一个选项失败,那么对每个选项都没有任何回溯。当前正则表达式的结构方式可以大大简化。我在“答案”部分提供了相应的修复程序。

Problem 6 - Spaces

See regex in use here

这本身可能不是一个问题,但它确实引起了大多数开发人员的关注。正则表达式中的空格不是可选的,这意味着输入邮政编码的用户必须在邮政编码中放置一个空格。这是一个简单的解决方法,只需在空格后添加?以使其可选。有关修复,请参阅“答案”部分。


Answer

1.修复英国政府的正则表达

修复“问题”部分中列出的所有问题并简化模式会产生以下更短,更简洁的模式。我们也可以删除大多数组,因为我们正在验证整个邮政编码(不是单个部分):

See regex in use here

^([A-Za-z][A-Ha-hJ-Yj-y]?[0-9][A-Za-z0-9]? ?[0-9][A-Za-z]{2}|[Gg][Ii][Rr] ?0[Aa]{2})$

通过从一种情况(大写或小写)中删除所有范围并使用不区分大小写的标记,可以进一步缩短这一点。注意:有些语言没有,所以请使用上面较长的语言。每种语言都以不同的方式实现大小写不敏感标记。

See regex in use here

^([A-Z][A-HJ-Y]?[0-9][A-Z0-9]? ?[0-9][A-Z]{2}|GIR ?0A{2})$

再次用[0-9]替换\d(如果你的正则表达式引擎支持它):

See regex in use here

^([A-Z][A-HJ-Y]?\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0A{2})$

2.简化模式

在不确保特定字母字符的情况下,可以使用以下内容(请记住简化1.修复英国政府的正则表达式也已应用于此处):

See regex in use here

^([A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0A{2})$

如果你不关心特殊情况GIR 0AA更进一步:

^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$

3.复杂的模式

我不建议对邮政编码进行过度验证,因为新的区域,区域和分区可能会在任何时间点出现。我建议可能做的是增加对边缘案例的支持。存在一些特殊情况,并在this Wikipedia article中列出。

这是复杂的正则表达式,包括3.(3.1,3.2,3.3)的小节。

关于1中的模式。修复英国政府的正则表达式:

See regex in use here

^(([A-Z][A-HJ-Y]?\d[A-Z\d]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?\d[A-Z]{2}|BFPO ?\d{1,4}|(KY\d|MSR|VG|AI)[ -]?\d{4}|[A-Z]{2} ?\d{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$

并且与2.简化模式有关:

See regex in use here

^(([A-Z]{1,2}\d[A-Z\d]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?\d[A-Z]{2}|BFPO ?\d{1,4}|(KY\d|MSR|VG|AI)[ -]?\d{4}|[A-Z]{2} ?\d{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$

3.1 British Overseas Territories

维基百科的文章目前陈述(某些格式略有简化):

  • AI-1111:安圭拉
  • ASCN 1ZZ:阿森松岛
  • STHL 1ZZ:圣赫勒拿岛
  • TDCU 1ZZ:Tristan da Cunha
  • BBND 1ZZ:英属印度洋领地
  • BIQQ 1ZZ:英属南极领土
  • FIQQ 1ZZ:福克兰群岛
  • GX11 1ZZ:直布罗陀
  • PCRN 1ZZ:皮特凯恩群岛
  • SIQQ 1ZZ:南乔治亚岛和南桑威奇群岛
  • TKCA 1ZZ:特克斯和凯科斯群岛
  • BFPO 11:Akrotiri和Dhekelia
  • ZZ 11GE CX:百慕大(根据this document
  • KY1-1111:开曼群岛(根据this document
  • VG1111:英属维尔京群岛(根据this document
  • MSR 1111:蒙特塞拉特(根据this document

仅与英国海外领土相匹配的无所不包的正则表达式可能如下所示:

See regex in use here

^((ASCN|STHL|TDCU|BBND|[BFS]IQQ|GX\d{2}|PCRN|TKCA) ?\d[A-Z]{2}|(KY\d|MSR|VG|AI)[ -]?\d{4}|(BFPO|[A-Z]{2}) ?\d{2}|GE ?CX)$

3.2 British Forces Post Office

虽然他们最近改变它以更好地与英国邮政编码系统对齐BF#(其中#代表一个数字),但它们被认为是可选的替代邮政编码。这些邮政编码遵循(编辑)BFPO的格式,后跟1-4位数字:

See regex in use here

^BFPO ?\d{1,4}$

3.3 Santa?

圣诞老人的另一个特例(如其他答案中所述):SAN TA1是一个有效的邮政编码。正则表达式非常简单:

^SAN ?TA1$

20
投票

我查看了上面的一些答案,我建议不要使用来自@ Dan的answer (c. Dec 15 '10)的模式,因为它错误地将几乎0.4%的有效邮政编码标记为无效,而其他人则没有。

Ordnance Survey提供名为Code Point Open的服务:

包含英国所有当前邮政编码单元的列表

我使用grep从这些数据中运行上面的每个正则表达式对照完整的邮政编码列表(2013年7月6日):

cat CSV/*.csv |
    # Strip leading quotes
    sed -e 's/^"//g' |
    # Strip trailing quote and everything after it
    sed -e 's/".*//g' |
    # Strip any spaces
    sed -E -e 's/ +//g' |
    # Find any lines that do not match the expression
    grep --invert-match --perl-regexp "$pattern"

总共有1,686,202个邮政编码。

以下是与每个$pattern不匹配的有效邮政编码的数量:

'^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]?[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$'
# => 6016 (0.36%)
'^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$'
# => 0
'^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|BX|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$'
# => 0

当然,这些结果只处理被错误标记为无效的有效邮政编码。所以:

'^.*$'
# => 0

我没有说过哪种模式最适合过滤掉无效的邮政编码。


17
投票
^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$

正则表达式匹配有效的英国邮政编码。在英国邮政系统中,并非所有位置都使用所有字母(与车辆登记牌相同),并且有各种规则来管理这一点。这个正则表达式考虑了这些规则。规则细节:邮政编码的前半部分有效格式[AZ] [AZ] [0-9] [AZ] [AZ] [AZ] [0-9] [0-9] [AZ] [0-9] [ 0-9] [AZ] [AZ] [0-9] [AZ] [AZ] [AZ] [AZ] [0-9] [AZ] [AZ] [0-9]例外位置 - 首先。约束 - QVX未使用位置 - 秒。 Contraint - IJZ除GIR 0AA位置外没有使用 - 第三。约束 - AEHMNPRTVXY仅使用Position - Forth。约束 - ABEHMNPRVWXY邮政编码的后半部分有效格式[0-9] [A-Z] [A-Z]例外位置 - 第二和第三。 Contraint - 未使用CIKMOV

http://regexlib.com/REDetails.aspx?regexp_id=260


14
投票

这里的大部分答案都不适用于我在数据库中的所有邮政编码。我终于找到了一个使用政府提供的新正则表达式验证所有人的方法:

https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/413338/Bulk_Data_Transfer_-_additional_validation_valid_from_March_2015.pdf

它不在以前的任何答案中,所以我在这里发布它以防止它们关闭链接:

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([A-Za-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$

更新:Jamie Bull指出的更新的正则表达式。不确定这是我的错误复制还是政府正则表达式中的错误,链接现在已经关闭...

更新:正如ctwheels发现的,这个正则表达式适用于javascript正则表达式风格。看看他对pcre(php)风格的评论。


12
投票

根据这个维基百科表

这种模式涵盖了所有情况

(?:[A-Za-z]\d ?\d[A-Za-z]{2})|(?:[A-Za-z][A-Za-z\d]\d ?\d[A-Za-z]{2})|(?:[A-Za-z]{2}\d{2} ?\d[A-Za-z]{2})|(?:[A-Za-z]\d[A-Za-z] ?\d[A-Za-z]{2})|(?:[A-Za-z]{2}\d[A-Za-z] ?\d[A-Za-z]{2})

在Android \ Java上使用时,请使用\\ d


12
投票

一个旧的帖子,但仍然相当高的谷歌搜索结果所以我认为我会更新。 10月14日的文档将英国邮政编码正则表达式定义为:

^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([**AZ**a-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z])))) [0-9][A-Za-z]{2})$

从:

https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/359448/4__Bulk_Data_Transfer_-_additional_validation_valid.pdf

该文件还解释了其背后的逻辑。但是,它有一个错误(粗体),也允许小写,虽然合法不常见,所以修改版本:

^(GIR 0AA)|((([A-Z][0-9]{1,2})|(([A-Z][A-HJ-Y][0-9]{1,2})|(([A-Z][0-9][A-Z])|([A-Z][A-HJ-Y][0-9]?[A-Z])))) [0-9][A-Z]{2})$

这适用于以前版本没有的新伦敦邮政编码(例如W1D 5LH)。

© www.soinside.com 2019 - 2024. All rights reserved.