我在一个正则表达式后,将验证一个完整的复杂的英国邮政编码只在输入字符串。所有不常见的邮政编码形式必须包括以及通常。例如:
匹配
CW3 9不锈钢 SE5 0EG SE50EG Se5 0eg WC2H 7LT
不匹配
aWC2H 7LT WC2H 7LTa WC2H
我怎么解决这个问题?
我在一个正则表达式后,将验证一个完整的复杂的英国邮政编码只在输入字符串。所有不常见的邮政编码形式必须包括以及通常。例如:
匹配
CW3 9不锈钢 SE5 0EG SE50EG Se5 0eg WC2H 7LT
不匹配
aWC2H 7LT WC2H 7LTa WC2H
我怎么解决这个问题?
当前回答
根据维基百科的表格
这种模式适用于所有情况
(?:[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
其他回答
不存在能够验证邮政编码的综合英国邮政编码正则表达式。您可以使用正则表达式检查邮政编码的格式是否正确;并不是真的存在。
邮政编码非常复杂,而且不断变化。例如,对于每个邮政编码区域,出码W1没有,也可能永远没有1到99之间的每个数字。
你不能指望当前的东西永远都是真的。举个例子,1990年,邮局认为阿伯丁有点拥挤了。他们在AB1-5的末尾加了一个0,使它成为AB10-50,然后在这些之间创建了一些邮政编码。
每当建立一条新街道时,就会创建一个新的邮政编码。这是获得建筑许可的过程的一部分;地方当局有义务与邮局保持更新(并不是说他们都这样做)。
此外,正如许多其他用户指出的那样,还有一些特殊的邮政编码,如Girobank, GIR 0AA,以及给圣诞老人的信件,SAN TA1 -你可能不想在那里张贴任何东西,但似乎没有任何其他答案。
然后,还有BFPO的邮政编码,现在正在改为更标准的格式。两种格式都是有效的。最后,还有海外领土来源维基百科。
+----------+----------------------------------------------+ | 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 releases Code-Point Open under an open data licence. It'll be very slightly behind the times but it's free. This will (probably - I can't remember) not include Northern Irish data as the Ordnance Survey has no remit there. Mapping in Northern Ireland is conducted by the Ordnance Survey of Northern Ireland and they have their, separate, paid-for, Pointer product. You could use this and append the few that aren't covered fairly easily. Royal Mail releases the Postcode Address File (PAF), this includes BFPO which I'm not sure Code-Point Open does. It's updated regularly but costs money (and they can be downright mean about it sometimes). PAF includes the full address rather than just postcodes and comes with its own Programmers Guide. The Open Data User Group (ODUG) is currently lobbying to have PAF released for free, here's a description of their position. Lastly, there's AddressBase. This is a collaboration between Ordnance Survey, Local Authorities, Royal Mail and a matching company to create a definitive directory of all information about all UK addresses (they've been fairly successful as well). It's paid-for but if you're working with a Local Authority, government department, or government service it's free for them to use. There's a lot more information than just postcodes included.
基本规则:
^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABD-HJLNP-UW-Z]{2}$
英国的邮政编码(或称为邮政编码)由5到7个字母数字字符组成,中间用空格隔开。规定哪些角色可以出现在特定位置的规则相当复杂,而且充满了例外。因此,刚才显示的正则表达式遵循基本规则。
完整的规则:
如果你需要一个以牺牲可读性为代价的正则表达式来满足所有的邮政编码规则,这里你可以:
^(?:(?:[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
在我们的客户数据库中进行了测试,似乎非常准确。
我最近发表了一个关于英国R语言邮政编码的答案。我发现英国政府的正则表达式模式是不正确的,不能正确地验证一些邮政编码。不幸的是,这里的许多答案都是基于这个错误的模式。
我将在下面概述其中的一些问题,并提供一个实际工作的修改后的正则表达式。
Note
我的回答(以及一般的正则表达式):
只验证邮政编码格式。 不能确保邮政编码合法存在。 为此,使用适当的API!更多信息请看本的回答。
如果你不关心糟糕的正则表达式,只想跳到答案,向下滚动到答案部分。
糟糕的正则表达式
不应使用本节中的正则表达式。
这是英国政府提供给开发者的失败正则表达式(不确定这个链接会持续多久,但你可以在他们的批量数据传输文档中看到它):
^([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的模式选项。有多少用户可能使用这个邮政编码而不是其他邮政编码;可能从来没有?这意味着每次使用正则表达式时,它必须先用完这个选项,然后再进行下一个选项。要了解性能如何受到影响,请检查在翻转选项(22)后,原始regex执行的步数(35)相对于相同的regex。
性能的第二个问题是由于整个正则表达式的结构方式。如果一个选项失败了,那么回溯每个选项就没有意义了。当前正则表达式的结构方式可以大大简化。我在答案部分提供了一个修复方法。
问题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](如果你的regex引擎支持它):
在这里查看正则表达式的使用。
^([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: Anguila 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 1ZZ: Gibraltar PCRN 1ZZ: Pitcairn Islands SIQQ 1ZZ: South Georgia and the South Sandwich Islands TKCA 1ZZ: Turks and Caicos Islands BFPO 11: Akrotiri and Dhekelia ZZ 11 & GE CX: Bermuda (according to this document) KY1-1111: Cayman Islands (according to this document) VG1111: British Virgin Islands (according to this document) MSR 1111: Montserrat (according to this document)
一个只匹配英国海外领土的包罗万象的正则表达式可能是这样的:
在这里查看正则表达式的使用。
^((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$
下面的方法将检查邮政编码并提供完整的信息
const isValidUKPostcode = 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,
message: 'It is a valid postcode'
};
} catch (error) {
return { error: true , message: 'Invalid postcode'};
}
};
console.log(isValidUKPostcode('GU348RR'))
{isValid: true, formattedPostcode: "GU34 8RR", error: false, message: "It is a valid postcode"}
console.log(isValidUKPostcode('sdasd4746asd'))
{error: true, message: "Invalid postcode!"}
valid_postcode('787898523')
result => {error: true, message: "Invalid postcode"}
我一直在寻找一个英国邮政编码正则表达式的最后一天左右,无意中发现了这个线程。我尝试了上面的大部分建议,但没有一个对我有用,所以我想出了自己的正则表达式,据我所知,它捕获了截至1月13日的所有有效的英国邮政编码(根据皇家邮政的最新文献)。
The regex and some simple postcode checking PHP code is posted below. NOTE:- It allows for lower or uppercase postcodes and the GIR 0AA anomaly but to deal with the, more than likely, presence of a space in the middle of an entered postcode it also makes use of a simple str_replace to remove the space before testing against the regex. Any discrepancies beyond that and the Royal Mail themselves don't even mention them in their literature (see http://www.royalmail.com/sites/default/files/docs/pdf/programmers_guide_edition_7_v5.pdf and start reading from page 17)!
注意:在皇家邮政自己的文献中(链接以上),第3和第4位的位置略有模糊,如果这些字符是字母,则例外。我直接联系了皇家邮政,用他们自己的话说,“AANA 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>";
}
?>
我希望它能帮助其他遇到这条线索寻找解决方案的人。