用于匹配英国邮政编码的正则表达式

239
我需要一个正则表达式来验证一个包含在输入字符串中的完整的英国邮编,包括所有不常见的邮编形式和通常的形式。例如:

匹配

  • CW3 9SS
  • SE5 0EG
  • SE50EG
  • se5 0eg
  • WC2H 7LT

不匹配

  • aWC2H 7LT
  • WC2H 7LTa
  • WC2H
如何解决这个问题?

2
@axrwkr,那看起来并不有帮助。 - Kieran Benton
8
英国邮编验证 - JavaScript 和 PHP 我无法使用接受的答案匹配有效的邮政编码,但我找到了这个,它可以匹配有效的邮政编码。对于客户端验证,JavaScript 版本可以直接使用;对于服务器端验证,将 JavaScript 重写为 C# 相对容易。它甚至重新格式化邮政编码以添加空格,因此如果你输入邮政编码 W1A1AA,它不仅会验证它,还会将其重新格式化为 W1A 1AA。它甚至处理了各种不寻常的来自英国领土的邮政编码。 - user2985029
2
提供的链接无法处理“AA1A 1AA”格式。参考:http://www.dhl.com.tw/content/dam/downloads/tw/express/forms/postcode_formats.pdf - Anthony Scaife
2
如果您只想验证邮政编码,我们提供一个免费(需要注册)的验证REST API端点 - http://developers.alliescomputing.com/postcoder-web-api/address-lookup/validate-postcode - Stephen Keable
1
好问题。我认为在您需要匹配的罕见示例列表中,包括曼彻斯特市中心邮政编码,例如“M1 3HZ”,是值得的。许多人不知道字母和数字组合的规则。 - Martin Joiner
1
这里的许多答案都基于英国政府提供的一个错误的正则表达式。有关这些问题的详细信息,请参阅我的答案 - ctwheels
33个回答

254

我建议您查看英国政府邮编数据标准 [链接已失效; XML的存档,请参见Wikipedia讨论]。该文提供了有关数据的简要描述,并且所附的xml模式提供了一个正则表达式。它可能并不完全符合您的需求,但是是一个很好的起点。该正则表达式与XML略有不同,因为在A9A 9AA格式的第三个位置上允许使用P字符。

英国政府提供的正则表达式是:

([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开头的编码),它们提供了一个更严格的测试,您可以尝试一下。


55
该正则表达式允许两个部分之间有可选的空格(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-HJKSTUW])|([A-Z-[QVX]][A-Z-[IJZ]][0-9][ABEHMNPRVWXY]))))\s?[0-9][A-Z-[CIKMOV]]{2})。 - gbro3n
7
为了避免页面每年过期的情况,将实际的正则表达式带到答案中可能是一个好主意。 - pauloya
7
请注意,此正则表达式适用于XML Schema,与其他正则表达式略有不同。 - artbristol
6
我无法在JavaScript中让它工作。它只能与某些正则表达式引擎一起使用吗? - NickG
20
实际上他们改了它:批量数据传输^([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})$ - wieczorek1990
显示剩余18条评论

228

我最近发布了一篇答案,是关于使用R语言处理英国邮政编码的这个问题。我发现英国政府的正则表达式模式是错误的,无法正确地验证一些邮政编码。不幸的是,这里许多答案都是基于这个错误的模式。

我将概述以下一些问题,并提供一个修订后的正则表达式,实际上可以工作。


注意

我的回答(以及正则表达式一般):

  • 仅验证邮政编码的格式
  • 不能保证邮政编码真实存在
    • 为此,请使用适当的API!有关更多信息,请参见Ben的回答

如果您不关心“坏的正则表达式”,只想跳到答案部分,请滚动到“答案”部分。
坏的正则表达式
这个部分的正则表达式不应该被使用。
这是英国政府提供给开发人员的失败正则表达式(不确定这个链接会存在多久,但您可以在他们的批量数据传输文档中看到它)。
^([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})$

问题

问题1 - 复制/粘贴

在此处查看使用的正则表达式

像许多开发人员一样,他们复制/粘贴代码(尤其是正则表达式)并期望它们能够正常工作。虽然这在理论上很好,但在这种特定情况下会失败,因为从本文档中复制/粘贴实际上会将一个字符(空格)更改为换行符,如下所示:

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

问题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})$
^^                     ^ ^                                                                                                                                            ^^

邮政编码正则表达式没有正确地锚定正则表达式。使用此正则表达式验证邮政编码的任何人可能会惊讶地发现像 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}))$
^^                                                                                                                                                                      ^^

问题3 - 不当的字符集

在此处查看使用的正则表达式

^([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代表数字),并且它以除A和Z之外的任何字符开头,它将失败。这意味着它将匹配A1A 1AA和Z1A 1AA,但不匹配B1A 1AA。要解决此问题,应在相应的字符集中的A和Z之间放置字符“-”。
^([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})$
                                                                                        ^

问题4 - 错误的可选字符集

在此处查看使用的正则表达式

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

问题 5 - 性能

这个正则表达式的性能非常差。首先,他们将最不可能匹配GIR 0AA的模式选项放在了开头。与任何其他邮政编码相比,有多少用户可能有这个邮政编码;可能从来没有?这意味着每次使用正则表达式时,它必须先耗尽这个选项,然后才能进入下一个选项。为了查看性能如何受到影响,请比较原始正则表达式所需的步骤数(35)与翻转选项后的相同正则表达式(22)。

性能的第二个问题是由整个正则表达式的结构方式引起的。如果一个失败了,回溯每个选项是没有意义的。当前正则表达式的结构方式可以大大简化。我在答案部分提供了一个解决方案。

问题 6 - 空格

在此处查看使用的正则表达式

这可能不被认为是一个问题,但它确实引起了大多数开发人员的关注。正则表达式中的空格不是可选的,这意味着输入邮政编码的用户必须在邮政编码中放置一个空格。通过在空格后添加?来使它们变成可选项,可以轻松解决这个问题。请参见答案部分以获取解决方案。


答案

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

解决问题部分中列出的所有问题并简化模式,可得到以下更短、更简洁的模式。由于我们正在验证邮政编码作为一个整体(而不是单个部分),因此可以删除大多数组:

在此处查看使用的正则表达式

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

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

在此处查看使用正则表达式

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

如果你的正则表达式引擎支持,使用\d替换[0-9]可以让正则表达式更加简洁:

在此处查看使用的正则表达式

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

2. 简化模式

如果不需要特定的字母字符,可以使用以下模式(请记住,1. 修复英国政府的正则表达式 中的简化也已应用于此处):

在此处查看使用的正则表达式

^([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. 复杂的模式

我不建议过度验证邮政编码,因为新的地区、区域和子区域可能随时出现。但我建议潜在地增加对边缘情况的支持。一些特殊情况存在,并在这篇维基百科文章中进行了概述。

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

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

在此处查看使用的正则表达式

^(([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. 简化模式

在这里查看正则表达式的使用

^(([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 英国海外领土

维基百科文章目前的陈述如下(部分格式稍作简化):

  • AI-1111: 安圭拉
  • ASCN 1ZZ: 阿森松岛
  • STHL 1ZZ: 圣赫勒拿
  • TDCU 1ZZ: 特里斯坦-达库尼亚群岛
  • BBND 1ZZ: 英属印度洋领地
  • BIQQ 1ZZ: 英属南极领地
  • FIQQ 1ZZ: 福克兰群岛
  • GX11 1ZZ: 直布罗陀
  • PCRN 1ZZ: 皮特凯恩群岛
  • SIQQ 1ZZ: 南乔治亚岛和南桑威奇群岛
  • TKCA 1ZZ: 特克斯和凯科斯群岛
  • BFPO 11: 阿克罗提里和德凯利亚
  • ZZ 11 & GE CX: 百慕大(参见此文件
  • KY1-1111: 开曼群岛(参见此文件
  • VG1111: 英属维尔京群岛(参见此文件
  • MSR 1111: 蒙特塞拉特(参见此文件

一个全面的正则表达式,仅匹配英国海外领土,可能看起来像这样:

在此处查看使用的正则表达式

^((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 英国部队邮政

尽管最近已经将其更改以更好地与英国邮政编码系统对齐为BF#(其中#代表数字),但它们被视为可选备用邮政编码。这些邮政编码遵循(曾经遵循)BFPO,后跟1-4个数字的格式:

在此处查看正则表达式

^BFPO ?\d{1,4}$

3.3 圣诞老人?

圣诞老人还有另外一个特殊情况(如其他答案中所提到的):SAN TA1是一个有效的邮政编码。匹配此项的正则表达式非常简单:

^SAN ?TA1$

7
简化的正则表达式是一个非常好的选项。我认为最好不要用过于严格的正则表达式,因为这样你需要确保它随着任何更改而更新,否则可能会让用户非常生气。我认为最好使用简单的正则表达式进行松散匹配,以筛除明显的错误,然后再应用进一步的检查,例如地址查询(或在电子邮件正则表达式的情况下,确认电子邮件),以确认其有效性。 - James Coyle
2
优秀而彻底的分析。 - Steve
3
在许多方面都是出色的回答。最终,我选择了你第二个简化模式。因为我实际上有一个包含所有英国邮政编码的数据库,所以我只需要进行第一次搜索,看看地址字符串是否可能包含有效的邮政编码,所以我不在意误报(因为实际查找将排除它们),但是我确实关心漏报。同时速度也很重要。 - John Powell
5
@Sunhat,我不喜欢人们称我的帖子为混乱,因为我清楚地详细说明了每个部分。我的回答提供了多种答案,因为一种解决方案并不能解决所有问题。例如,正则表达式引擎都是实现不同的,所以虽然“\d”在大多数情况下可行,但并非所有情况都适用。此外,英国政府指定字符范围而不是整个字母表,并且不同的邮政编码格式存在于军事、岛屿等方面。仅有这三个标准,就会得到6种版本。我认为我在回答问题方面做得很好,还有超过120个人同意我的观点。 - ctwheels
1
这对我非常有帮助;我只需要从电子邮件数据中提取类似邮政编码的内容,所以我使用了... [A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}。然而,解释清晰明确,是SO帖子应该具备的光辉榜样,五颗星! - Steve Hibbert
显示剩余10条评论

86

看起来我们将使用^(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模式XML Schema,其中提供了邮政编码规则的“伪正则表达式”语句。

我们采用了这个语句并稍作修改,得到了以下表达式:

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

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

可以接受以下格式:

  • “GIR 0AA”
  • A9 9ZZ
  • A99 9ZZ
  • AB9 9ZZ
  • AB99 9ZZ
  • A9C 9ZZ
  • AD9E 9ZZ

其中:

  • 数字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之外的任何字母。

祝一切顺利

Colin


2
很棒的答案,我添加了海外的 ^(([gG][iI][rR] {0,}0[aA]{2})|(([aA][sS][cC][nN]|[sS][tT][hH][lL]|[tT][dD][cC][uU]|[bB][bB][nN][dD]|[bB][iI][qQ][qQ]|[fF][iI][qQ][qQ]|[pP][cC][rR][nN]|[sS][iI][qQ][qQ]|[iT][kK][cC][aA]) {0,}1[zZ]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yxA-HK-XY]?[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}))$ - David Bradshaw
为什么在指定无限可选空格时要使用{0,}而不是* - Code Animal

48

没有一个完整的英国邮政编码正则表达式可以验证邮政编码。您可以使用正则表达式检查邮政编码是否处于正确的格式,但不能检查它是否真实存在。

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

您不能期望当前的情况永远不变。例如,在1990年,邮局认为阿伯丁有点拥挤。他们在AB1-5的末尾添加了0,使其成为AB10-50,然后创建了许多介于这些之间的邮政编码。

每当建造新街道时,都会创建一个新的邮政编码。这是获得建筑许可的过程的一部分;地方当局有义务将此与邮局保持更新(并非所有地方当局都这样做)。

此外,正如其他用户所指出的那样,还有特殊的邮政编码,例如Girobank、GIR 0AA以及给圣诞老人的信的邮政编码SAN TA1 - 您可能不想将任何东西寄到那里,但似乎没有其他答案涵盖了这些编码。

然后,还有 BFPO 邮政编码,现在更改为更标准的格式。两种格式都将有效。最后,还有海外领土来源维基百科
+----------+----------------------------------------------+
| 邮政编码 |                   位置                       |
+----------+----------------------------------------------+
| AI-2640  | 安圭拉                                       |
| ASCN 1ZZ | 阿森松岛                                     |
| STHL 1ZZ | 圣赫勒拿                                     |
| TDCU 1ZZ | 特里斯坦-达库尼亚                            |
| BBND 1ZZ | 英属印度洋领地                               |
| BIQQ 1ZZ | 英属南极领地                                 |
| FIQQ 1ZZ | 福克兰群岛                                   |
| GX11 1AA | 直布罗陀                                     |
| PCRN 1ZZ | 皮特凯恩群岛                                 |
| SIQQ 1ZZ | 南乔治亚岛和南桑威奇群岛                     |
| TKCA 1ZZ | 特克斯和凯科斯群岛                           |
+----------+----------------------------------------------+
下一步,您需要考虑到英国将其邮政编码系统“导出”到世界上许多地方。任何验证“英国”邮政编码的东西也会验证其他许多国家/地区的邮政编码。
如果您想要验证一个英国邮政编码,最安全的方法是使用当前邮政编码的查找。有几个选项:
Ordnance Survey发布Code-Point Open的开放数据许可证。虽然它会略微滞后一些,但是它是免费的。这可能不包括北爱尔兰的数据,因为Ordnance Survey在那里没有管辖权。北爱尔兰的地图绘制由北爱尔兰Ordnance Survey进行,他们有自己的Pointer产品,需要付费。您可以轻松使用此产品并附加未覆盖的部分。
皇家邮政发布Postcode Address File(PAF),其中包括我不确定Code-Point Open是否包含BFPO的数据。它定期更新,但需要花费资金(有时他们可能非常吝啬)。 PAF包括完整地址而不仅仅是邮政编码,并配有自己的Programmers Guide。 开放数据用户组(ODUG)目前正在游说免费发布PAF,这里是他们的立场描述
最后,还有AddressBase。这是Ordnance Survey,地方政府,皇家邮政和匹配公司之间的合作,旨在创建有关所有英国地址的所有信息的定义性目录(他们相当成功)。需要付费,但如果您与地方政府,政府部门或政府服务机构合作,则对他们免费使用。包括的信息不仅仅是邮政编码。

查询听起来很有趣。 - SuperUberDuper
2
虽然这不是 OP 寻找的答案,但它可能是最有用的。这将鼓励我放松我要做的检查规则。 - John Hunt

22
^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$
匹配英国有效邮政编码的正则表达式。在英国邮政系统中,并不是所有字母都可以用于所有位置(车辆注册牌照也一样),而且有各种规定来管理这些。该正则表达式将考虑这些规定。规则的详细信息:邮政编码的前半部分的有效格式为 [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] [A-Z] [A-Z] [0-9] [A-Z] [0-9] [A-Z] [0-9]。例外情况有: 位置-第一位。限制-QVX不使用 位置-第二位。限制-IJZ除GIR 0AA外不使用 位置-第三位。限制-AEHMNPRTVXY仅使用 位置-第四位。限制-ABEHMNPRVWXY 邮政编码的后半部分的有效格式为[0-9][A-Z][A-Z]。例外情况有:位置-第二和第三位。限制-CIKMOV不使用。http://regexlib.com/REDetails.aspx?regexp_id=260

1
不知道为什么有人给这个答案点了踩 - 它是正确的正则表达式。 - Ollie
正则表达式在JavaScript中无法匹配邮政编码“YO31”和“YO31 1”。 - Pratik Khadloya
9
我认为这是不正确的,因为给定的正则表达式与描述相矛盾,并暗示您可以拥有以 0-9 开头的邮政编码,而实际上不能。 - Luigi Plinge
4
这个正则表达式无法匹配大约6000个有效的邮编,所以我建议不要使用它。请参阅我的答案 - RichardTowers
这对于任何小写或没有空格的邮政编码都会失败。 - Dancer
为了使这些正则表达式变得更易于管理,它们往往支持大写或小写邮政编码,但不支持两者同时存在。文档始终使用大写字母。从验证的角度来看,您可以编写支持其中一种情况的代码,并根据需要更改大小写。关于空格问题,文档指出:“第一部分或外部代码与第二部分或内部代码之间用一个空格隔开”-因此需要该空格。 - Zhaph - Ben Duguid

21

我查看了上面的一些答案,不建议使用@Dan的答案(约为2010年12月15日)中的模式,因为它错误地将近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

我并不会说明哪种模式是最好的,以过滤掉无效的邮政编码为例。


1
这不就是我在答案中说的吗?如果你要走反驳的路线,那么你应该把它们全部做完,并且如果有人更改了他们的答案,你应该及时更新。如果没有,至少引用最后一次编辑答案的日期,这样人们就可以看到它是否已经被更改过了。 - Ben
公正的观点。已做出相应修改。我认为指出这些模式大多不排除任何CPO代码是有益于讨论的,但最受赞同的(有效的正则表达式)答案却排除了其中一些。未来的读者请注意,我的结果可能已经过时。 - RichardTowers

13

这里大部分答案并不能适用于我数据库中的所有邮政编码。最终我找到了一个可以验证所有邮编的新正则表达式,该正则表达式由政府提供:

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)语法的一个。


1
^([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})|(([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
1
非常准确!我更新了我的回答。谢谢! - Jesús Carrera
2
这是唯一一个在http://www.regexr.com/和Notepad++中都能正常工作的答案。 虽然我必须将它更改为([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})(已删除^$并在空格后添加了一个?)以便http://www.regexr.com/可以找到多个结果,并且对于两个查询,可以找到没有空格分隔符的结果。 - mythofechelon
1
文档中发布的正则表达式本质上是不正确的。整个表达式应该被包裹在一个非捕获组 (?:) 中,然后再放置锚定点。在这里可以看到它失败了:https://regex101.com/r/KleL5c/1。更多信息请参见我的答案:https://dev59.com/Mq3la4cB1Zd3GeqPPp5i#51828886。^(?:([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}))$ 是已校正的正则表达式。 - ctwheels
@JesúsCarrera 我上面发布的正则表达式是许多语言(不仅限于PCRE)的修正版本。这是PHP、JavaScript、Python等语言的修正版本。 - ctwheels
显示剩余5条评论

13
根据这个维基百科的表格。 enter image description here 这种模式涵盖了所有情况。
(?:[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


我认为这是最易读的答案,尽管它只查找邮政编码的形式,而不是像从gov.uk网站获取信息的解决方案那样查找实际有效的代码,但对于我的用例来说已经足够了。在使用Python进行一些操作后,我将其分解为稍微更紧凑但等效的正则表达式,该表达式还允许可选空格:(a-zA-Z\W?[0-9][a-zA-Z]{2}) - Richard J

12

这是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}

12

这是一篇老文章,但在谷歌搜索结果中排名仍然很高,所以我想更新一下。该文档定义了英国邮编正则表达式:

^([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),而先前的版本则不适用。


看起来你在文档中加粗标记的错误已经被修复了,但我仍然更喜欢你的正则表达式,因为它更易读。 - Professor of programming
5
我唯一想说的是,将空格更改为 \s? 可以使空格变为可选项,因为空格并不是必须的,这样做可以提高可读性。 - Professor of programming
文档中发布的正则表达式本质上是不正确的。整个表达式应该被包裹在一个非捕获组 (?:) 中,然后再放置锚定点。在这里可以看到它失败了:https://regex101.com/r/KleL5c/1。更多信息请参见我的答案:https://dev59.com/Mq3la4cB1Zd3GeqPPp5i#51828886。^(?:([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}))$ 是已校正的正则表达式。 - ctwheels

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