没有正则表达式的英国(GB)邮政编码验证

Tib*_*tan 13 php postal-code

我已经尝试了几个正则表达式,但有时候一些有效的邮政编码会被拒绝.

搜索互联网,维基百科和SO,我只能找到正则表达式验证解决方案.

有没有使用正则表达式的验证方法?在任何语言中,我想这很容易移植.

我认为最简单的方法是与邮政编码数据库进行比较,但需要从可靠的来源定期维护和更新.

编辑:为了帮助未来的访问者并让你不再发布任何正则表达式,这里是我测试的一个正则表达式(截至2013-04-24),适用于Code Point中的所有邮政编码(请参阅@MikkelLøkke的回答):

//PHP PCRE (it was on Wikipedia, it isn't there anymore; I might have modified it, don't remember).
$strPostalCode=preg_replace("/[\s]/", "", $strPostalCode);
$bValid=preg_match("/^(GIR 0AA)|(((A[BL]|B[ABDHLNRSTX]?|C[ABFHMORTVW]|D[ADEGHLNTY]|E[HNX]?|F[KY]|G[LUY]?|H[ADGPRSUX]|I[GMPV]|JE|K[ATWY]|L[ADELNSU]?|M[EKL]?|N[EGNPRW]?|O[LX]|P[AEHLOR]|R[GHM]|S[AEGKLMNOPRSTY]?|T[ADFNQRSW]|UB|W[ADFNRSV]|YO|ZE)[1-9]?[0-9]|((E|N|NW|SE|SW|W)1|EC[1-4]|WC[12])[A-HJKMNPR-Y]|(SW|W)([2-9]|[1-9][0-9])|EC[1-9][0-9])[0-9][ABD-HJLNP-UW-Z]{2})$/i", $strPostalCode);
Run Code Online (Sandbox Code Playgroud)

Ham*_*mZa 21

我正在根据维基页面写这个答案.

检查验证部分时,似乎有6种格式(A =字母,9 =数字):

AA9A 9AA                       AA9A9AA                   AA9A9AA
A9A 9AA     Removing space     A9A9AA       order it     AA999AA
A9 9AA    ------------------>  A99AA     ------------->  AA99AA
A99 9AA                        A999AA                    A9A9AA
AA9 9AA                        AA99AA                    A999AA
AA99 9AA                       AA999AA                   A99AA
Run Code Online (Sandbox Code Playgroud)

我们可以看到,长度可能从5到7不等,如果我们愿意,我们必须考虑一些特殊情况.

所以我们编写的函数必须执行以下操作:

  1. 删除空格并转换为大写(或小写).
  2. 检查输入是否是异常,如果是,则返回有效
  3. 检查输入的长度是否为4 <长度< 8.
  4. 检查它是否是有效的邮政编码.

最后一部分很棘手,但我们将按长度分为3个部分进行概述:

  1. 长度= 7:AA9A9AAAA999AA
  2. 长度= 6:AA99AA,A9A9AAA999AA
  3. 长度= 5:A99AA

为此我们将使用一个switch().从现在开始,如果它是正确位置的字母或数字,则只需逐个字符检查即可.

那么让我们来看看我们的PHP实现:

function check_uk_postcode($string){
    // Start config
    $valid_return_value = 'valid';
    $invalid_return_value = 'invalid';
    $exceptions = array('BS981TL', 'BX11LT', 'BX21LB', 'BX32BB', 'BX55AT', 'CF101BH', 'CF991NA', 'DE993GG', 'DH981BT', 'DH991NS', 'E161XL', 'E202AQ', 'E202BB', 'E202ST', 'E203BS', 'E203EL', 'E203ET', 'E203HB', 'E203HY', 'E981SN', 'E981ST', 'E981TT', 'EC2N2DB', 'EC4Y0HQ', 'EH991SP', 'G581SB', 'GIR0AA', 'IV212LR', 'L304GB', 'LS981FD', 'N19GU', 'N811ER', 'NG801EH', 'NG801LH', 'NG801RH', 'NG801TH', 'SE18UJ', 'SN381NW', 'SW1A0AA', 'SW1A0PW', 'SW1A1AA', 'SW1A2AA', 'SW1P3EU', 'SW1W0DT', 'TW89GS', 'W1A1AA', 'W1D4FA', 'W1N4DJ');
    // Add Overseas territories ?
    array_push($exceptions, 'AI-2640', 'ASCN1ZZ', 'STHL1ZZ', 'TDCU1ZZ', 'BBND1ZZ', 'BIQQ1ZZ', 'FIQQ1ZZ', 'GX111AA', 'PCRN1ZZ', 'SIQQ1ZZ', 'TKCA1ZZ');
    // End config


    $string = strtoupper(preg_replace('/\s/', '', $string)); // Remove the spaces and convert to uppercase.
    $exceptions = array_flip($exceptions);
    if(isset($exceptions[$string])){return $valid_return_value;} // Check for valid exception
    $length = strlen($string);
    if($length < 5 || $length > 7){return $invalid_return_value;} // Check for invalid length
    $letters = array_flip(range('A', 'Z')); // An array of letters as keys
    $numbers = array_flip(range(0, 9)); // An array of numbers as keys

    switch($length){
        case 7:
            if(!isset($letters[$string[0]], $letters[$string[1]], $numbers[$string[2]], $numbers[$string[4]], $letters[$string[5]], $letters[$string[6]])){break;}
            if(isset($letters[$string[3]]) || isset($numbers[$string[3]])){
                return $valid_return_value;
            }
        break;
        case 6:
            if(!isset($letters[$string[0]], $numbers[$string[3]], $letters[$string[4]], $letters[$string[5]])){break;}
            if(isset($letters[$string[1]], $numbers[$string[2]]) || isset($numbers[$string[1]], $letters[$string[2]]) || isset($numbers[$string[1]], $numbers[$string[2]])){
                return $valid_return_value;
            }
        break;
        case 5:
            if(isset($letters[$string[0]], $numbers[$string[1]], $numbers[$string[2]], $letters[$string[3]], $letters[$string[4]])){
                return $valid_return_value;
            }
        break;
    }

    return $invalid_return_value;
}
Run Code Online (Sandbox Code Playgroud)

请注意,我没有添加英国邮政局非地理代码.

用法:

echo check_uk_postcode('AE3A 6AR').'<br>'; // valid
echo check_uk_postcode('Z9 9BA').'<br>'; // valid
echo check_uk_postcode('AE3A6AR').'<br>'; // valid
echo check_uk_postcode('EE34      6FR').'<br>'; // valid
echo check_uk_postcode('A23A 7AR').'<br>'; // invalid
echo check_uk_postcode('A23A   7AR').'<br>'; // invalid
echo check_uk_postcode('WA3334E').'<br>'; // invalid
echo check_uk_postcode('A2 AAR').'<br>'; // invalid
Run Code Online (Sandbox Code Playgroud)


fla*_*ian 6

由英国政府提供.

   (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])))) [0-9][A-Z-[CIKMOV]]{2})
Run Code Online (Sandbox Code Playgroud)

我使用我从这里获得的邮政编码在伦敦建立了仅基于邮政编码的应用程序.但说实话,即使只使用伦敦邮政编码,您也需要更多的存储空间.当然,这个想法是微不足道的.

存储邮政编码,获取用户输入或其他内容,看看是否匹配.但是你的解决方案比你想象的要复杂得多.我必须使用实际的邮政编码来实现我想要的,但是为了简单的验证目的,像"维护"正则表达式一样难,存储数万或数十万(如果不是更多)并且实时或多或少地验证是一项艰巨的任务.

如果一个迷你分布式服务听起来像一个比正则表达式更有效的解决方案,那就去吧,但我确定它不是.除非你需要根据英国邮政编码或类似的东西对你自己的数据进行地理空间查询,否则我怀疑数据库存储是一个可行的解决方案.只需2美分.

更新

根据指数,英国有1,758,417个邮政编码.我可以告诉你,我正在使用一些Mongo集群(Amazon EC2高内存实例)来提供可靠的仅限伦敦的服务(仅索引伦敦邮政编码),即使使用基本存储,它也是非常昂贵的.

不可否认,该应用程序正在执行中等复杂度的地理空间查询,但仅存储要求非常昂贵且要求苛刻.

最重要的是,坚持使用正则表达式并在两分钟内完成.