高效的正则表达式用于加拿大邮政编码函数

61
var regex = /[A-Za-z]\d[A-Za-z] ?\d[A-Za-z]\d/;
var match = regex.exec(value);
if (match){
    if ( (value.indexOf("-") !== -1 || value.indexOf(" ") !== -1 ) && value.length() == 7 ) {
        return true;
    } else if ( (value.indexOf("-") == -1 || value.indexOf(" ") == -1 ) && value.length() == 6 ) {
        return true;
    }
} else {
        return false;
}

正则表达式查找"A0A 1B1"模式。 正确的测试:

A0A 1B1

A0A-1B1

A0A1B1

A0A1B1C <<问题所在

因此,我添加了一个检查"-"或者" "的条件,然后再检查长度。

是否存在更有效的方法或正则表达式?


1
如果您正在为用户输入而进行此操作,请不要过于严格。最近我在一家(FAANG)网站上浪费了时间,因为我没有包括空格,该网站告诉我我的邮政编码无效。人类不是计算机,我们并没有都阅读过邮政编码的规范。 - user3064538
7个回答

78

用户类型、邮政编码限制,最高效的格式:

/^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][ -]?\d[ABCEGHJ-NPRSTV-Z]\d$/i

允许:

  • h2t-1b8
  • h2z 1b8
  • H2Z1B8

禁止:

  • Z2T 1B8(以Z开头)
  • H2T 1O3(包含O)

不能以Z、W开头或包含D、F、I、O、Q或U


正则表达式结尾的 'i' 是打错了还是整个正则表达式的一部分? - Pawel Cioch
2
https://dev59.com/oW445IYBdhLWcg3wO31u - Dan
出现错误:在使用stringr()中的str_extract时,“/ ^ [ABCEGHJ-NPRSTVXY] \ d”中的“\ d”是无法识别的转义字符。 - robbieNukes

50

为您的模式添加锚点:

var regex = /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/;

^表示字符串的开头,$表示字符串的结尾。添加这些锚点将防止C滑入匹配,因为您的模式现在期望整个字符串由6个(有时7个-作为空格)字符组成。这个额外的好处现在应该让您免于随后检查字符串长度。

另外,由于您希望允许连字符,您可以将其放入一个可选的字符类中,其中包括您最初使用的空格。确保将连字符保留为第一个或最后一个字符; 否则,您将需要转义它(使用前导反斜杠),以防止正则表达式引擎将其解释为字符范围的一部分(例如A-Z)。


4
我来翻译一下,他也可以使用i标记,这样就不需要进行显式的大小写检查了。 - Dave
11
这将允许无效的加拿大邮政编码。 邮政编码从不以可能被误认为是数字的字符开头:I,O,Q,U,W,Z ... 因此: /^[ABCEGHJKLMNPRSTVXY]\d[ -]?\d[A-Za-z]\d$/; - Ben A. Hilleli
3
有趣,但我想知道:如果邮政编码总是以字母开头,为什么会将上述任何字母与数字混淆?W会被混淆成什么数字?我相信这些都是邮政服务的问题 :) - Kenneth K.
2
/^[ABCEGHJ-NPRSTVXY][0-9][ABCEGHJ-NPRSTV-Z] [0-9][ABCEGHJ-NPRSTV-Z][0-9]$/ 是一个更严格的正则表达式。 - Vincent D'amour
1
邮政编码可以包含W或Z,但不能在第一个位置,因为第一个字母代表18个邮政区之一(每个省一个,但安大略省有5个,魁北克省有3个)。您可以在此处查看:https://en.wikipedia.org/wiki/Postal_codes_in_Canada#Table_of_all_postal_codes。 - Félix Brunet
显示剩余2条评论

29

这个可以处理我们和加州的代码。

function postalFilter (postalCode) {

    if (! postalCode) {
        return null;
    }

    postalCode = postalCode.toString().trim();

    var us = new RegExp("^\\d{5}(-{0,1}\\d{4})?$");
    var ca = new RegExp(/([ABCEGHJKLMNPRSTVXY]\d)([ABCEGHJKLMNPRSTVWXYZ]\d){2}/i);

    if (us.test(postalCode.toString())) {
        return postalCode;
    }

    if (ca.test(postalCode.toString().replace(/\W+/g, ''))) {
        return postalCode;
    }
    return null;
}

// these 5 return null
console.log(postalFilter('1a1 a1a'));
console.log(postalFilter('F1A AiA'));
console.log(postalFilter('A12345-6789'));
console.log(postalFilter('W1a1a1')); // no "w"
console.log(postalFilter('Z1a1a1')); // ... or "z" allowed in first position!

// these return canada postal less space
console.log(postalFilter('a1a 1a1'));
console.log(postalFilter('H0H 0H0'));

// these return unaltered
console.log(postalFilter('H0H0H0'));
console.log(postalFilter('a1a1a1'));
console.log(postalFilter('12345'));
console.log(postalFilter('12345-6789'));
console.log(postalFilter('123456789'));

// strip spaces
console.log(postalFilter(' 12345 '));

3
这个答案中的正则表达式比目前接受的答案更加干净且准确,因为加拿大邮政编码总是省略 D、F、I、O、Q 和 U 这些字母。/([ABCEGHJKLMNPRSTVWXYZ]\d){3}/i不过有一个条件被遗漏了,即第一个字母不能是 W 或 Z。 https://zh.wikipedia.org/wiki/%E5%8A%A0%E6%8B%BF%E5%A4%A7%E9%82%AE%E6%94%BF%E7%BC%96%E7%A0%81#cite_note-2 - Robert Penner
@RobertPenner 是正确的。我纠正了加拿大邮政编码的正则表达式。但我敢打赌,应该有更好的方法来做这件事。 - lysdexia

18
您在正则表达式方面遇到了问题,StatsCan发布了有关有效加拿大邮政编码的规则:
邮政编码是由加拿大邮政公司(CPC)定义和维护的六个字符代码,用于分拣和投递邮件。这些字符以“ANA NAN”的形式排列,其中“A”代表字母字符,“N”代表数字字符(例如,K1A 0T6)。邮政编码使用18个字母字符和10个数字字符。邮政编码不包括字母D、F、I、O、Q或U,而且第一个位置也不使用字母W或Z。
如果您想要严格匹配,则应该使用正则表达式。
/^[ABCEGHJ-NPRSTVXY][0-9][ABCEGHJ-NPRSTV-Z] [0-9][ABCEGHJ-NPRSTV-Z][0-9]$/

同时\d表示数字,不一定是0-9,可能有一个错误的浏览器将其视为Unicode空间中的任何数字,这可能会在下游给您带来问题。

来源:https://trajano.net/2017/05/canadian-postal-code-validation/


0

这是一个函数,可以一次性为您完成所有操作。接受带有或不带有空格的AAA BBB和AAABBB。

function go_postal(){
        let postal = $("#postal").val();
        var regex = /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/;
        var pr = regex .test(postal);
        if(pr === true){
            //all good          
        } else {
            // not so much
        }
    }

-1
function postalFilter (postalCode, type) {

    if (!postalCode) {
        return null;
    }

    postalCode = postalCode.toString().trim();

    var us = new RegExp("^\\d{5}(-{0,1}\\d{4})?$");
   // var ca  = new RegExp(/^((?!.*[DFIOQU])[A-VXY][0-9][A-Z])|(?!.*[DFIOQU])[A-VXY][0-9][A-Z]\ ?[0-9][A-Z][0-9]$/i);
    var ca = new RegExp(/^[ABCEGHJKLMNPRSTVXY]\d[ABCEGHJKLMNPRSTVWXYZ]( )?\d[ABCEGHJKLMNPRSTVWXYZ]\d$/i);

    if(type == "us"){
        if (us.test(postalCode.toString())) {
            console.log(postalCode);
            return postalCode;
        }
    }

    if(type == "ca")
    {
        if (ca.test(postalCode.toString())) {
            console.log(postalCode);
            return postalCode;
        }
    }

    return null;
}

-1
regex = new RegExp(/^[ABCEGHJ-NPRSTVXY]\d[ABCEGHJ-NPRSTV-Z][-]?\d[ABCEGHJ-NPRSTV-Z]\d$/i);
if(regex.test(value))
    return true;
else
    return false;

这是原问题的简化版本,其中value是任何文本值。此外,无需测试值的长度。


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