13

私はいくつかの正規表現を試しましたが、まだいくつかの有効な郵便番号が拒否されることがあります。

インターネット、ウィキペディア、および SO を検索すると、正規表現検証ソリューションしか見つかりませんでした。

正規表現を使用しない検証方法はありますか? どの言語でも、移植は簡単だと思います。

郵便番号データベースと比較するのが最も簡単だと思いますが、信頼できる情報源から定期的に維持および更新する必要があります。

編集:将来の訪問者を助け、これ以上正規表現を投稿しないようにするために、コードポイントのすべての郵便番号で機能するように(2013-04-24の時点で)テストした正規表現を次に示します(@Mikkel Lø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);
4

8 に答える 8

22

wikiページに基づいてこの回答を書いています。

検証部分を確認すると、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

ご覧のとおり、長さは 5 から 7 まで変化する可能性があり、必要に応じていくつかの特殊なケースを考慮する必要があります。

したがって、コーディングしている関数は次のことを行う必要があります。

  1. スペースを削除し、大文字 (または小文字) に変換します。
  2. 入力が例外かどうかを確認し、例外である場合は有効な値を返す必要があります
  3. 入力の長さが 4 <長さ< 8 であるかどうかを確認します。
  4. 有効な郵便番号かどうかを確認します。

最後の部分はややこしいですが、概要を説明するために、長さによって 3 つのセクションに分割します。

  1. 長さ = 7: AA9A9AAおよびAA999AA
  2. 長さ = 6: AA99AAA9A9AA、およびA999AA
  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;
}

英国軍の郵便局非地理的なコードを追加していないことに注意してください。

使用法:

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
于 2013-04-30T15:42:21.973 に答える
2

現在、ウィキペディアで英国の郵便番号のリンクを見ています。

http://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom

検証セクションには、文字と数字を組み合わせた 6 つの形式がリストされています。それから、その下のメモに詳細があります。私が最初に試すのは、GoldParserBuilder のようなツールを使用した BNF 型の文法です。効率的なパーサーとレクサーが自動的に生成され、基本的な形式をより読みやすい形式で記述することができます。過去に、私はそのようなツールをうまく使って、巨大で醜い正規表現を書くことを避けてきました。

その時点から、プログラムは既知のタイプの適切にフォーマットされた郵便番号を持っています。この時点で、特定の数字または文字が何かに違反している可能性があります。郵便番号の種類ごとに、その特定の種類の違反を探すようにプログラムされた機能を持つことができます。最終製品は、検証されていないが構造化/識別された郵便番号を専用の検証関数に渡す、自動生成されたパーサーで構成されます。その後、そこからリファクタリングまたは最適化できます。

(文法自体を使用して、特定のリテラルや組み合わせを強制または禁止することもできます。より読みやすく理解しやすいものは何でも。さまざまな人がこれらのさまざまな目的に引き寄せられます。)

これは、GOLD 解析システムの利点を強調したページです。好きなものを使用できます。私は、その仕事が得意で、長年にわたって着実に改善されてきたこの 1 つを宣伝します。 http://www.goldparser.org/about/why-use-gold.htm

于 2013-04-17T23:21:13.387 に答える
2

正規表現はデバッグが難しく、ある正規表現から別の正規表現への移植が難しく (サイレント「エラー」)、更新が困難です。

これはほとんどの正規表現に当てはまりますが、複数の部分に分割してみませんか? 6 つの異なる一般的なルールについては、簡単に 6 つの部分に分割できます。すべての特殊なケースを考慮に入れると、さらに多くの部分に分割できます。

単純な正規表現を使用して 20 行の適切にコメントされたメソッドを作成すると、デバッグが容易になり (1 行に 1 つの単純な正規表現)、更新も容易になります。移植の問題は同じですが、一方で、凝った文法ライブラリを使用する必要はありません。

于 2013-04-22T15:39:36.067 に答える
1

サードパーティのサービスはオプションですか?

http://www.postcodeanywhere.co.uk/address-validation/

GeoNames データベース:

http://www.geonames.org/postal-codes/

于 2013-04-22T16:02:28.590 に答える
0

有効な郵便番号のリストを取得し、入力した郵便番号がその中にあるかどうかを確認します。

于 2013-04-22T15:29:13.817 に答える