Проверка почтового индекса Соединенного Королевства (GB) без регулярного выражения

Я пробовал несколько регулярных выражений, и некоторые действительные почтовые коды иногда отклоняются.

Поиск в Интернете, Wikipedia и SO, я мог найти только решения для проверки регулярных выражений.

Есть ли метод проверки, который не использует регулярное выражение? На любом языке, я думаю, его было бы легко переносить.

Я считаю, что самым простым было бы сравнение с базой данных почтового кода, но это необходимо было бы периодически поддерживать и обновлять с надежного источника.

Изменить: Чтобы помочь будущим посетителям и не давать вам больше публиковать регулярные выражения, здесь регулярное выражение, которое я тестировал (начиная с 2013-04-24), для работы со всеми почтовыми кодами в Code Point (см. ответ @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);

Ответ 1

Я пишу этот ответ на странице 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, и мы должны учитывать некоторые особые случаи, если хотим.

Итак, функция, которую мы кодируем, должна сделать следующее:

  • Удалить пробелы и преобразовать в верхний регистр (или в нижний регистр).
  • Проверьте, является ли вход исключением, если он должен вернуть действительный
  • Проверьте, соответствует ли длина ввода 4 < длина < 8.
  • Проверьте, является ли он действительным почтовым индексом.

Последняя часть сложна, но мы разделим ее на 3 секции по длине для некоторого обзора:

  • Длина = 7: AA9A9AA и AA999AA
  • Длина = 6: AA99AA, A9A9AA и A999AA
  • Длина = 5: A99AA

Для этого мы будем использовать a 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

Ответ 2

Как предоставлено правительством Великобритании.

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

Я построил только приложения на основе почтового индекса в Лондоне, используя почтовые индексы, которые я получил от ЗДЕСЬ. Но, честно говоря, даже с лондонскими почтовыми индексами вам нужно гораздо больше места, чем необходимо. Конечно, идея тривиальна.

Сохраните почтовые индексы, возьмите пользовательский ввод или что-то еще, и посмотрите, получилось ли совпадение. Но вы усложняете решение гораздо больше, чем думаете. Я хотел использовать фактические почтовые индексы для достижения того, что я хотел, но для простых целей проверки так же сложно, как "поддерживать" регулярное выражение, хранить десятки тысяч или сотни тысяч (если не больше) и более или менее достоверно проверять в режиме реального времени это гораздо более сложная задача.

Если мини-распределенное обслуживание звучит как более эффективное решение, чем регулярное выражение, пойдите для него, но я уверен, что это не так. Если вам не нужны геопространственные запросы ваших собственных данных к британским почтовым индексам или тому подобное, я сомневаюсь, что хранилище DB является приемлемым решением. Только мои 2 цента.

Обновление

Согласно индексу this, в Великобритании есть 1 758 417 почтовых индексов. Я могу сказать, что я использую несколько кластеров Mongo (Amazon EC2 High Memory Instances), чтобы обеспечить надежные услуги только для Лондона (индексирование только лондонских почтовых индексов), и это довольно дорого, даже с базовым хранилищем.

По общему признанию, приложение выполняет геопространственные запросы средней сложности, но требования к хранению сами по себе очень дороги и требуют.

В нижней строке, просто придерживайтесь регулярного выражения и делайте это через две минуты.

Ответ 3

Я смотрю на ссылку "Почтовые индексы в Соединенном Королевстве" в Википедии прямо сейчас.

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

В разделе "Проверка" перечислены шесть форматов с комбинацией букв и цифр. Затем в примечаниях ниже содержится больше информации. Первое, что я попробую, это грамматика типа BNF с помощью инструмента, такого как GoldParserBuilder. Вы можете описать базовые форматы в более читаемом формате, при этом автоматически создаются эффективный парсер и лексер. Раньше я успешно использовал такие инструменты, чтобы избежать написания огромных, уродливых регулярных выражений.

С этой точки программа имеет правильно отформатированный почтовый индекс известного типа. На данный момент конкретные цифры или буквы могут что-то нарушить. Каждый тип почтового индекса может иметь функцию, запрограммированную на поиск нарушений определенного типа. Конечный продукт будет состоять из автоматически созданного синтаксического анализатора, который передает неутвержденные, но структурированные/идентифицированные почтовые индексы в специальную функцию проверки. Затем вы можете реорганизовать или оптимизировать.

(Вы также можете использовать грамматику, чтобы обеспечить или запретить определенные литералы и комбинации. Что бы ни было более читаемым или понятным для вас. Различные люди тяготеют к разным концам этих вещей.)

Вот страница, в которой подчеркиваются преимущества GOLD Parsing System. Вы можете использовать любые, которые вам нравятся: я просто продвигаю этот б/н, который хорошо работает на своей работе и неуклонно улучшался в течение многих лет. http://www.goldparser.org/about/why-use-gold.htm

Ответ 4

Я бы подумал, что RegEX, хотя долгожданный, вероятно, будет лучшим решением, если все, что вы хотите сделать, - это проверить, может ли что-то быть допустимым почтовым кодом Великобритании.

Если вам нужны абсолютные данные, подумайте об использовании инициативы OpenData Ordnance Survey "" Код-точка® Открыть", который представляет собой CSV большого количества точки данных в Великобритании (так что не Северная Ирландия, я предполагаю), один из которых является почтовым индексом. Имейте в виду, что файл составляет 20 МБ, поэтому вам, возможно, придется преобразовать его в более управляемый формат.

Ответ 5

Regexes трудно отлаживать, трудно переносить от одного цвета регулярного выражения к другому (молчащие "ошибки" ) и трудно обновить.

Это верно для большинства регулярных выражений, но почему бы вам просто не разбить его на несколько частей? Вы можете легко разделить его на шесть частей для шести разных общих правил и, возможно, даже больше, если учитывать все особые случаи.

Создание хорошо прокомментированного метода из 20 строк с простыми регулярными выражениями легко отлаживается (одно простое регулярное выражение для каждой строки), а также легко обновляется. Проблема с портированием одинакова, но, с другой стороны, вам не нужно использовать какую-нибудь фантастическую грамматическую библиотеку.

Ответ 7

+1 для комментариев "зачем". Мне пришлось использовать "официальное" регулярное выражение в различных проектах, и, хотя я никогда не пытался его сломать, он работает, и он выполняет эту работу. Я использовал его с Java и PHP-кодом без необходимости конвертировать его между форматами регулярных выражений.

Есть ли причина, по которой вам придется отлаживать ее или ломать ее?

Кстати, правило регулярных выражений находилось в википедии, но, похоже, оно исчезло.

Изменить: что касается обсуждения пространства/без пробела, почтовый индекс должен быть действительным с пространством или без него. Поскольку последняя часть почтового индекса (после пробела) ВСЕГДА состоит из трех цифр, можно вставить пространство вручную, что позволит вам запустить его через правило регулярного выражения.

Ответ 8

Возьмите список допустимых почтовых индексов и проверьте, находится ли он в нем.