Я недавно опубликовал ответ на этот вопрос на британских почтовых индексов для языка R . Я обнаружил, что шаблон регулярных выражений правительства Великобритании неверен и не может правильно проверить некоторые почтовые индексы. К сожалению, многие ответы здесь основаны на этой неправильной схеме.
Я изложу некоторые из этих вопросов ниже и предоставлю исправленное регулярное выражение, которое действительно работает.
Заметка
Мой ответ (и регулярные выражения в целом):
- Проверяет только форматы почтовых индексов .
- Не гарантирует, что почтовый индекс законно существует .
- Для этого используйте соответствующий API! Смотрите ответ Бена для получения дополнительной информации.
Если вас не интересует плохое регулярное выражение, и вы просто хотите пропустить ответ, прокрутите вниз до раздела « Ответ ».
Плохое регулярное выражение
Регулярные выражения в этом разделе не должны использоваться.
Это ошибочное регулярное выражение, которое правительство Великобритании предоставило разработчикам (не уверен, как долго будет действовать эта ссылка, но вы можете увидеть это в их документации Bulk Data Transfer ):
^([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})$
^
Я клянусь, что они даже не проверяли эту вещь, прежде чем публиковать ее в Интернете. Они сделали неправильный набор символов необязательным. Они сделали [0-9]вариант в четвертом подопции варианта 2 (группа 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в начале. Сколько пользователей будет иметь этот почтовый индекс по сравнению с любым другим почтовым индексом; наверное никогда? Это означает, что каждый раз, когда используется регулярное выражение, он должен сначала исчерпать эту опцию, прежде чем перейти к следующей. Чтобы увидеть, как это влияет на производительность, проверьте количество шагов, которые исходное регулярное выражение (35) предприняло по отношению к тому же регулярному выражению после переключения опций (22).
Вторая проблема с производительностью связана с тем, как структурировано все регулярное выражение. Там нет смысла возвращаться к каждому варианту, если один не удастся. Структура текущего регулярного выражения может быть значительно упрощена. Я исправляю это в разделе « Ответ ».
Задача 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})$
Короче снова заменить [0-9]на \d(если ваш движок регулярных выражений поддерживает это):
Смотрите регулярное выражение в использовании здесь .
^([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: Ангилья
ASCN 1ZZ: Остров Вознесения
STHL 1ZZ: Святой Елены
TDCU 1ZZТристан-да-Кунья
BBND 1ZZ: Британская территория Индийского океана
BIQQ 1ZZ: Британская Антарктическая Территория
FIQQ 1ZZ: Фолклендские острова
GX11 1ZZ: Гибралтар
PCRN 1ZZ: Острова Питкэрн
SIQQ 1ZZ: Южная Георгия и Южные Сандвичевы острова
TKCA 1ZZ: Острова Теркс и Кайкос
BFPO 11: Акротири и Декелия
ZZ 11& GE CX: Бермудские острова (согласно этому документу )
KY1-1111: Каймановы острова (согласно этому документу )
VG1111: Британские Виргинские острова (согласно этому документу )
MSR 1111: Монтсеррат (согласно этому документу )
Всеобъемлющее регулярное выражение для соответствия только британским заморским территориям может выглядеть так:
Смотрите регулярное выражение в использовании здесь .
^((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#(где #представляет число), они считаются необязательными альтернативными почтовыми индексами . Эти почтовые индексы следуют (ed) формат BFPO, за которым следуют 1-4 цифры:
Смотрите регулярное выражение в использовании здесь
^BFPO ?\d{1,4}$
3.3 Санта?
Есть еще один особый случай с Сантой (как уже упоминалось в других ответах): SAN TA1это действительный почтовый индекс. Регулярное выражение для этого очень просто:
^SAN ?TA1$