RegEx para códigos postais do Reino Unido correspondentes

186

Estou atrás de um regex que validará um código postal completo e complexo do Reino Unido somente dentro de uma sequência de entrada. Todos os formulários incomuns de códigos postais devem ser cobertos, além do usual. Por exemplo:

Partidas

  • CW3 9SS
  • SE5 0EG
  • SE50EG
  • se5 0eg
  • WC2H 7LT

Sem correspondência

  • aWC2H 7LT
  • WC2H 7LTa
  • WC2H

Como eu resolvo este problema?

Kieran Benton
fonte
2
@axrwkr que não parece útil
Kieran Benton
8
Validação de código postal no Reino Unido - JavaScript e PHP Não consegui obter a resposta aceita para corresponder a códigos postais válidos, mas encontrei isso e corresponde a códigos postais válidos. Para validação no lado do cliente, a versão JavaScript pode ser usada como está, para validação no servidor, reescrever o JavaScript como C # é bastante simples. Ele até reformata o código postal para ter um espaço; portanto, se você inserir um código postal como W1A1AA, além de validar, ele será reformatado para W1A 1AA. Ele até lida com códigos postais incomuns em vários territórios britânicos.
2
O link fornecido não funciona para os formatos "AA1A 1AA". Referência: dhl.com.tw/content/dam/downloads/tw/express/forms/…
Anthony Scaife
1
Se você simplesmente deseja validar um código postal, oferecemos um ponto de extremidade da API REST de validação gratuito ( developers.alliescomputing.com/postcoder-web-api/address-lookup/…
Stephen Keable 14/15/15
1
Boa pergunta. Eu acho que valeria a pena incluir um código postal central de Manchester como "M1 3HZ" na sua lista de exemplos incomuns que precisam corresponder. Muitas pessoas não estão cientes dos combos de 1 letra 1 número.
Martin Joiner

Respostas:

208

Eu recomendaria dar uma olhada no UK Government Data Standard para códigos postais [link now dead; arquivo XML , veja Wikipedia para discussão]. Há uma breve descrição sobre os dados e o esquema xml anexado fornece uma expressão regular. Pode não ser exatamente o que você deseja, mas seria um bom ponto de partida. O RegEx difere um pouco do XML, pois um caractere P na terceira posição no formato A9A 9AA é permitido pela definição fornecida.

O RegEx fornecido pelo governo do Reino Unido era:

([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]?))))\s?[0-9][A-Za-z]{2})

Como apontado na discussão da Wikipedia, isso permitirá alguns códigos postais não reais (por exemplo, aqueles que iniciam AA, ZY) e fornecem um teste mais rigoroso que você poderia tentar.

Brian Campbell
fonte
52
E que reg ex com um espaço em branco opcional entre os dois segmentos (GIR 0AA) | ((([AZ- [QVX]] [0-9] [0-9]?) | (([AZ- [QVX]]) [AZ- [IJZ]] [0-9] [0-9]?) | (([AZ- [QVX]] [0-9] [A-HJKSTUW]) | ([AZ- [QVX]]] [ AZ- [IJZ]] [0-9] [ABEHMNPRVWXY])))) \ s? [0-9] [AZ- [CIKMOV]] {2})
gb2d
7
Pode ser uma boa ideia para trazer a regex real para a resposta, uma vez que as páginas parecem expiram a cada ano ...
pauloya
7
Note que este regex é para XML Schema, que é, obviamente, um pouco diferente de outros sabores regex
artbristol
6
Não consigo fazer isso funcionar em JavaScript. Funciona apenas com certos mecanismos regex?
NickG
12
Na verdade, eles mudaram: Transferência de dados em massa :^([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})$
wieczorek1990
85

Parece que vamos usar ^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$, que é uma versão ligeiramente modificada daquela sugerida por Minglis acima.

No entanto, teremos que investigar exatamente quais são as regras, pois as várias soluções listadas acima parecem aplicar regras diferentes às quais letras são permitidas.

Após algumas pesquisas, encontramos mais algumas informações. Aparentemente, uma página em 'govtalk.gov.uk' aponta para uma especificação de código postal govtalk-postcodes . Isso aponta para um esquema XML no XML Schema que fornece uma instrução 'pseudo regex' das regras de código postal.

Pegamos isso e trabalhamos um pouco para nos dar a seguinte expressão:

^((GIR &0AA)|((([A-PR-UWYZ][A-HK-Y]?[0-9][0-9]?)|(([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y]))) &[0-9][ABD-HJLNP-UW-Z]{2}))$

Isso torna os espaços opcionais, mas limita você a um espaço (substitua 'e' por '{0,} para espaços ilimitados). Ele assume que todo o texto deve estar em maiúsculas.

Se você deseja permitir letras minúsculas, com qualquer número de espaços, use:

^(([gG][iI][rR] {0,}0[aA]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y]))) {0,}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2}))$

Isso não abrange territórios no exterior e apenas reforça o formato, NÃO a existência de áreas diferentes. É baseado nas seguintes regras:

Pode aceitar os seguintes formatos:

  • "GIR 0AA"
  • A9 9ZZ
  • A99 9ZZ
  • AB9 9ZZ
  • AB99 9ZZ
  • A9C 9ZZ
  • AD9E 9ZZ

Onde:

  • 9 pode ser qualquer número de um dígito.
  • A pode ser qualquer letra, exceto Q, V ou X.
  • B pode ser qualquer letra, exceto I, J ou Z.
  • C pode ser qualquer letra, exceto I, L, M, N, O, P, Q, R, V, X, Y ou Z.
  • D pode ser qualquer letra, exceto I, J ou Z.
  • E pode ser qualquer um de A, B, E, H, M, N, P, R, V, W, X ou Y.
  • Z pode ser qualquer letra, exceto C, I, K, M, O ou V.

Muitas felicidades

Colin

Colin
fonte
2
Ótima resposta, eu adicionei nos estrangeiros^(([gG][iI][rR] {0,}0[aA]{2})|(([aA][sS][cC][nN]|[sS][tT][hH][lL]|[tT][dD][cC][uU]|[bB][bB][nN][dD]|[bB][iI][qQ][qQ]|[fF][iI][qQ][qQ]|[pP][cC][rR][nN]|[sS][iI][qQ][qQ]|[iT][kK][cC][aA]) {0,}1[zZ]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yxA-HK-XY]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y]))) {0,}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2}))$
David Bradshaw
Por que especificar em {0,}vez de *espaços opcionais e ilimitados?
Code Animal
76

Eu recentemente postou uma resposta para esta pergunta em códigos postais do Reino Unido para a linguagem R . Descobri que o padrão de regex do governo do Reino Unido está incorreto e falha ao validar corretamente alguns códigos postais. Infelizmente, muitas das respostas aqui são baseadas neste padrão incorreto.

Vou descrever alguns desses problemas abaixo e fornecer uma expressão regular revisada que realmente funciona.


Nota

Minha resposta (e expressões regulares em geral):

  • Valida apenas os formatos de código postal .
  • Não garante que um código postal exista legitimamente .

Se você não se importa com a regex incorreta e deseja apenas pular para a resposta, role para baixo até a seção Resposta .

The Bad Regex

As expressões regulares nesta seção não devem ser usadas.

Este é o regex com falha que o governo do Reino Unido forneceu aos desenvolvedores (não sabe quanto tempo esse link ficará ativo, mas você pode vê-lo na documentação da Transferência de dados em massa ):

^([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})$

Problemas

Problema 1 - Copiar / Colar

Veja regex em uso aqui .

Como muitos desenvolvedores provavelmente copiam / colam código (especialmente expressões regulares) e os colam esperando que funcionem. Embora isso seja ótimo em teoria, ele falha neste caso específico, porque copiar / colar deste documento realmente altera um dos caracteres (um espaço) para um caractere de nova linha, como mostrado abaixo:

^([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})$

A primeira coisa que a maioria dos desenvolvedores fará é apagar a nova linha sem pensar duas vezes. Agora, a regex não corresponderá aos códigos postais com espaços (exceto o GIR 0AAcódigo postal).

Para corrigir esse problema, o caractere de nova linha deve ser substituído pelo caractere de espaço:

^([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})$
                                                                                                                                                     ^

Problema 2 - Limites

Veja regex em uso aqui .

^([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})$
^^                     ^ ^                                                                                                                                            ^^

O código postal regex ancora incorretamente o regex. Qualquer pessoa que use esse regex para validar códigos postais pode se surpreender se um valor como o fooA11 1AApassar. Isso ocorre porque eles ancoraram o início da primeira opção e o final da segunda opção (independentemente uma da outra), conforme apontado no regex acima.

O que isso significa é que ^(afirma a posição no início da linha) funciona apenas na primeira opção ([Gg][Ii][Rr] 0[Aa]{2}); portanto, a segunda opção validará todas as strings que terminam em um código postal (independentemente do que vem antes).

Da mesma forma, a primeira opção não está ancorada no final da linha $, GIR 0AAfootambém é aceita.

^([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})$

Para corrigir esse problema, as duas opções devem ser agrupadas em outro grupo (ou grupo que não captura) e as âncoras colocadas em torno dele:

^(([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}))$
^^                                                                                                                                                                      ^^

Problema 3 - Conjunto de caracteres inadequado

Veja regex em uso aqui .

^([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})$
                                                                                       ^^

O regex está ausente -aqui para indicar um intervalo de caracteres. Tal como está, se um código postal estiver no formato ANA NAA(onde Arepresenta uma letra e Num número) e começar com algo diferente de Aou Z, falhará.

Isso significa que corresponderá A1A 1AAe Z1A 1AA, mas não B1A 1AA.

Para corrigir esse problema, o caractere -deve ser colocado entre Ae Zno respectivo conjunto de caracteres:

^([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})$
                                                                                        ^

Problema 4 - Conjunto de caracteres opcional errado

Veja regex em uso aqui .

^([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})$
                                                                                                                                        ^

Juro que eles nem testaram isso antes de publicá-lo na web. Eles tornaram o conjunto de caracteres errado opcional. Eles fizeram a [0-9]opção na quarta subopção da opção 2 (grupo 9). Isso permite que o regex corresponda a códigos postais formatados incorretamente, como AAA 1AA.

Para corrigir esse problema, torne opcional a próxima classe de caractere (e subseqüentemente faça o conjunto [0-9]corresponder exatamente uma vez):

^([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})$
                                                                                                                                                ^

Problema 5 - Desempenho

O desempenho nesse regex é extremamente ruim. Primeiro, eles colocaram a opção de padrão menos provável de corresponder GIR 0AAno início. Quantos usuários provavelmente terão esse código postal em comparação com qualquer outro código postal; provavelmente nunca? Isso significa que toda vez que a regex é usada, ela deve esgotar essa opção antes de prosseguir para a próxima opção. Para ver como o desempenho é afetado, verifique o número de etapas que a regex original executou (35) na mesma regex após ter invertido as opções (22).

O segundo problema com o desempenho se deve à maneira como toda a regex está estruturada. Não faz sentido voltar atrás em cada opção se uma falhar. A maneira como o regex atual é estruturado pode ser bastante simplificada. Eu forneço uma correção para isso na seção Resposta .

Problema 6 - Espaços

Veja regex em uso aqui

Isso pode não ser considerado um problema , por si só, mas gera preocupação para a maioria dos desenvolvedores. Os espaços no regex não são opcionais, o que significa que os usuários que inserem seus códigos postais devem colocar um espaço no código postal. Essa é uma solução fácil, basta adicionar ?após os espaços para torná-los opcionais. Consulte a seção Resposta para uma correção.


Responda

1. Corrigindo o Regex do governo do Reino Unido

A correção de todos os problemas descritos na seção Problemas e a simplificação do padrão produz o seguinte padrão, mais curto e conciso. Também podemos remover a maioria dos grupos, pois estamos validando o código postal como um todo (não partes individuais):

Veja regex em uso aqui

^([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})$

Isso pode ser reduzido ainda mais, removendo todos os intervalos de um dos casos (maiúsculas ou minúsculas) e usando um sinalizador que não diferencia maiúsculas de minúsculas. Nota : Alguns idiomas não têm um, portanto, use o mais longo acima. Cada idioma implementa o sinalizador de distinção entre maiúsculas e minúsculas de maneira diferente.

Veja regex em uso aqui .

^([A-Z][A-HJ-Y]?[0-9][A-Z0-9]? ?[0-9][A-Z]{2}|GIR ?0A{2})$

Shorter novamente substituindo [0-9]com \d(se o seu motor regex suporta):

Veja regex em uso aqui .

^([A-Z][A-HJ-Y]?\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0A{2})$

2. Padrões simplificados

Sem garantir caracteres alfabéticos específicos, é possível usar o seguinte (lembre-se das simplificações de 1. A correção do Regex do governo do Reino Unido também foi aplicada aqui):

Veja regex em uso aqui .

^([A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}|GIR ?0A{2})$

E ainda mais se você não se importa com o caso especial GIR 0AA:

^[A-Z]{1,2}\d[A-Z\d]? ?\d[A-Z]{2}$

3. Padrões complicados

Eu não sugeriria a verificação excessiva de um código postal, pois novas áreas, distritos e subdistritos podem aparecer a qualquer momento. O que eu sugiro fazer potencialmente é o suporte adicional para casos extremos. Alguns casos especiais existem e são descritos neste artigo da Wikipedia .

Aqui estão as expressões regulares complexas que incluem as subseções de 3. (3.1, 3.2, 3.3).

Em relação aos padrões em 1. Fixing Regex do governo do Reino Unido :

Veja regex em uso aqui

^(([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)$

E em relação a 2. Padrões simplificados :

Veja regex em uso aqui

^(([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 Territórios ultramarinos britânicos

O artigo da Wikipedia afirma atualmente (alguns formatos ligeiramente simplificados):

  • AI-1111: Anguila
  • ASCN 1ZZ: Ilha da Ascensão
  • STHL 1ZZ: Santa Helena
  • TDCU 1ZZ: Tristan da Cunha
  • BBND 1ZZ: Território Britânico do Oceano Índico
  • BIQQ 1ZZ: Território Antártico Britânico
  • FIQQ 1ZZ: Ilhas Malvinas
  • GX11 1ZZ: Gibraltar
  • PCRN 1ZZ: Ilhas Pitcairn
  • SIQQ 1ZZ: Ilhas Geórgia do Sul e Sandwich do Sul
  • TKCA 1ZZ: Ilhas Turcas e Caicos
  • BFPO 11: Akrotiri e Dhekelia
  • ZZ 11& GE CX: Bermuda (de acordo com este documento )
  • KY1-1111: Ilhas Cayman (de acordo com este documento )
  • VG1111: Ilhas Virgens Britânicas (de acordo com este documento )
  • MSR 1111: Montserrat (de acordo com este documento )

Um regex abrangente para corresponder apenas aos Territórios Ultramarinos Britânicos pode ser assim:

Veja regex em uso aqui .

^((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 Correios das forças britânicas

Embora tenham sido alterados recentemente para melhor alinhar-se ao sistema de código postal britânico para BF#(onde #representa um número), eles são considerados códigos postais alternativos opcionais . Esses códigos postais seguem (ed) o formato de BFPO, seguido por 1 a 4 dígitos:

Veja regex em uso aqui

^BFPO ?\d{1,4}$

3.3 Papai Noel?

Há outro caso especial com o Papai Noel (como mencionado em outras respostas): SAN TA1é um código postal válido. Um regex para isso é muito simples:

^SAN ?TA1$
ctwheels
fonte
4
Os padrões simplificados são uma boa opção para usar. Eu acho que é melhor não ser muito restritivo com um regex, pois você precisa garantir que ele seja atualizado com todas as alterações ou você pode ter usuários muito irritados. Acho melhor combinar com um regex simplificado para eliminar os erros óbvios e depois aplicar verificações adicionais, como uma pesquisa de endereço (ou email de confirmação no caso de regex de email) para confirmar a validade.
James Coyle
2
Análise excelente e completa.
24519 Steve
1
Resposta brilhante em muitos níveis. Por fim, fui com seu segundo padrão simplificado. Como na verdade tenho um banco de dados com todos os códigos postais do Reino Unido, só preciso de uma primeira passagem para ver se uma sequência de endereços contém potencialmente um código postal válido, por isso não me importo com falsos positivos (pois a pesquisa real os eliminará) , mas me importo com falsos negativos. E a velocidade também é importante.
John Powell
Existem muitos problemas com o sistema de códigos postais do Reino Unido, manifestamente criado pelo comitê antes da era dos computadores, mas a questão do tamanho e espaços variáveis ​​é uma das mais perniciosas. Eu já vi todo tipo de horrores, incluindo códigos postais de preenchimento como E1 5JX a E1 5JX, ou seja, com três espaços, para que ele se alinhe perfeitamente ao SW18 5HA no Excel (insira um software hediondo e inapropriado para gerenciar endereços). A única solução sã, IMHO, é remover todos os espaços, para que o código postal seja uma única sequência antes de chegar perto de Elastic, Solr, Postgres etc.
John Powell
45

Não existe uma expressão regular abrangente de código postal do Reino Unido capaz de validar um código postal. Você pode verificar se um código postal está no formato correto usando uma expressão regular; não que ele realmente exista.

Os códigos postais são arbitrariamente complexos e mudam constantemente. Por exemplo, o código de saída W1não tem e pode nunca ter todos os números entre 1 e 99, para cada área de código postal.

Você não pode esperar que o que existe atualmente seja verdadeiro para sempre. Como exemplo, em 1990, os Correios decidiram que Aberdeen estava ficando um pouco lotado. Eles adicionaram um 0 ao final do AB1-5, tornando-o AB10-50 e, em seguida, criaram vários códigos postais entre eles.

Sempre que uma nova rua é construída, um novo código postal é criado. Faz parte do processo para obter permissão para construir; as autoridades locais são obrigadas a manter isso atualizado com os Correios (não que todos o façam).

Além disso, como observado por vários outros usuários, existem os códigos postais especiais, como o Girobank, o GIR 0AA e o de cartas para o Papai Noel, SAN TA1 - você provavelmente não deseja publicar nada lá, mas parece que não ser coberto por qualquer outra resposta.

Depois, há os códigos postais do BFPO, que agora estão mudando para um formato mais padrão . Ambos os formatos serão válidos. Por fim, há a fonte de territórios no exterior da Wikipedia .

+ ---------- + -------------------------------------- -------- +
| Código Postal | Localização |
+ ---------- + -------------------------------------- -------- +
| AI-2640 Anguilla
| ASCN 1ZZ Ilha da Ascensão |
| STHL 1ZZ Santa Helena
| TDCU 1ZZ Tristão da Cunha
| BBND 1ZZ | Território Britânico do Oceano Índico |
| BIQQ 1ZZ Território Antártico Britânico |
| FIQQ 1ZZ Ilhas Falkland |
| GX11 1AA | Gibraltar
| PCRN 1ZZ Ilhas Pitcairn |
| SIQQ 1ZZ Ilhas Geórgia do Sul e Sandwich do Sul |
| TKCA 1ZZ Ilhas Turks e Caicos |
+ ---------- + -------------------------------------- -------- +

Em seguida, você deve levar em conta que o Reino Unido "exportou" seu sistema de códigos postais para muitos lugares do mundo. Qualquer coisa que valide um código postal do "Reino Unido" também validará os códigos postais de vários outros países.

Se você deseja validar um código postal do Reino Unido, a maneira mais segura de fazer isso é usar uma pesquisa dos códigos postais atuais. Há uma série de opções:

  • O Ordnance Survey libera o Code-Point Open sob uma licença de dados abertos. Vai ser um pouco atrasado, mas é grátis. Isso (provavelmente - não me lembro) não incluirá dados da Irlanda do Norte, pois o Ordnance Survey não tem remessas para lá. O mapeamento na Irlanda do Norte é conduzido pelo Ordnance Survey da Irlanda do Norte e eles têm seu produto Pointer separado e pago . Você pode usar isso e anexar os poucos que não são abordados com bastante facilidade.

  • O Royal Mail lança o PAF (Postcode Address File) , que inclui o BFPO, que não tenho certeza se o Code-Point Open faz. É atualizado regularmente, mas custa dinheiro (e às vezes pode ser totalmente mesquinho). O PAF inclui o endereço completo em vez de apenas códigos postais e vem com seu próprio Guia do Programador . O Grupo de Usuários de Dados Abertos (ODUG) está atualmente fazendo lobby para que o PAF seja liberado gratuitamente, aqui está uma descrição de sua posição .

  • Por fim, há AddressBase . Esta é uma colaboração entre a Ordnance Survey, as autoridades locais, o Royal Mail e uma empresa correspondente para criar um diretório definitivo de todas as informações sobre todos os endereços do Reino Unido (eles também tiveram bastante sucesso). É pago, mas se você estiver trabalhando com uma autoridade local, departamento do governo ou serviço do governo, é gratuito para eles usarem. Há muito mais informações do que apenas códigos postais incluídos.

Ben
fonte
o olhar até parece interessante
SuperUberDuper
2
Embora essa não seja a resposta que a operação estava procurando, é provavelmente a mais útil. Isso me incentivará a relaxar as regras de verificação que vou fazer.
John Hunt
22

Analisei algumas das respostas acima e recomendo não usar o padrão da resposta de @ Dan (c. 15/12/10) , pois sinaliza incorretamente quase 0,4% dos códigos postais válidos como inválidos, enquanto os outros não. .

O Ordnance Survey fornece um serviço chamado Code Point Open que:

contém uma lista de todas as unidades de código postal atuais na Grã-Bretanha

Executei cada uma das regexs acima na lista completa de códigos postais (6 de julho de 13) a partir desses dados usando grep:

cat CSV/*.csv |
    # Strip leading quotes
    sed -e 's/^"//g' |
    # Strip trailing quote and everything after it
    sed -e 's/".*//g' |
    # Strip any spaces
    sed -E -e 's/ +//g' |
    # Find any lines that do not match the expression
    grep --invert-match --perl-regexp "$pattern"

Existem 1.686.202 códigos postais no total.

A seguir, são apresentados os números de códigos postais válidos que não correspondem a cada um $pattern:

'^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]?[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$'
# => 6016 (0.36%)
'^(GIR ?0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]([0-9ABEHMNPRV-Y])?)|[0-9][A-HJKPS-UW]) ?[0-9][ABD-HJLNP-UW-Z]{2})$'
# => 0
'^GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|BX|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}$'
# => 0

Obviamente, esses resultados lidam apenas com códigos postais válidos que são sinalizados incorretamente como inválidos. Assim:

'^.*$'
# => 0

Não estou dizendo nada sobre qual padrão é o melhor para filtrar códigos postais inválidos.

RichardTowers
fonte
1
Não é isso o que digo na minha resposta e, se você estiver seguindo o caminho da reprovação, provavelmente deve fazer todos eles e mantê-lo atualizado se alguém alterar sua resposta? Caso contrário, pelo menos faça referência à data da última edição da resposta que você recebeu para que as pessoas possam ver se ela foi alterada desde então.
Ben
Ponto justo. Editado de acordo. Eu acho que acrescenta à discussão salientar que a maioria desses padrões não exclui nenhum dos códigos de CPO, mas que a resposta mais votada (regex válida) o faz. Futuros leitores: saiba que meus resultados provavelmente estão desatualizados.
21813 RichardTowers
17
^([A-PR-UWYZ0-9][A-HK-Y0-9][AEHMNPRTVXY0-9]?[ABEHMNPRVWXY0-9]? {1,2}[0-9][ABD-HJLN-UW-Z]{2}|GIR 0AA)$

Expressão regular para corresponder a códigos postais do Reino Unido válidos. No sistema postal do Reino Unido, nem todas as letras são usadas em todas as posições (o mesmo com as matrículas dos veículos) e existem várias regras para governar isso. Este regex leva em consideração essas regras. Detalhes das regras: Primeira metade do código postal Formatos válidos [AZ] [AZ] [0-9] [AZ] [AZ] [AZ] [0-9] [0-9] [AZ] [0-9] [ 0-9] [AZ] [AZ] [0-9] [AZ] [AZ] [AZ] [AZ] [0-9] [AZ] [AZ] [0-9] Exceções Posição - primeiro. Contraint - QVX não usado Posição - Segundo. Contraint - IJZ não usado, exceto na posição GIR 0AA - Terceiro. Restrição - AEHMNPRTVXY usou apenas a Posição - Adiante. Contraint - ABEHMNPRVWXY Segunda metade do código postal Formatos válidos [0-9] [AZ] [AZ] Exceções Posição - segunda e terceira. Contraint - CIKMOV não usado

http://regexlib.com/REDetails.aspx?regexp_id=260

Dan
fonte
1
Não faço ideia por que as pessoas têm downvoted esta resposta - é a regex correto
Ollie
A regex não funciona para os códigos postais "YO31" e "YO31 1" em Javscript.
Pratik Khadloya
9
Eu não acho que isso é correto, uma vez que a regex contradiz dada a descrição, e sugere que você pode ter códigos postais começando com 0-9, que você não pode
Luigi Plinge
4
Esse regex falha em cerca de 6000 códigos postais válidos, por isso recomendo. Veja minha resposta .
21813 RichardTowers
isto falhar em qualquer código postal em minúsculas ou sem um espaço para mim
Dancer
14

De acordo com esta tabela da Wikipedia

insira a descrição da imagem aqui

Esse padrão cobre todos os casos

(?:[A-Za-z]\d ?\d[A-Za-z]{2})|(?:[A-Za-z][A-Za-z\d]\d ?\d[A-Za-z]{2})|(?:[A-Za-z]{2}\d{2} ?\d[A-Za-z]{2})|(?:[A-Za-z]\d[A-Za-z] ?\d[A-Za-z]{2})|(?:[A-Za-z]{2}\d[A-Za-z] ?\d[A-Za-z]{2})

Ao usá-lo no Android \ Java, use \\ d

AntPachon
fonte
Achei a resposta mais legível, embora apenas procure a forma de um código postal, em vez de códigos válidos reais, de acordo com as soluções que extraem as informações do site gov.uk, mas isso é bom o suficiente para o meu caso de uso. Depois de brincar um pouco (em python), considerei um regex um pouco mais compacto, mas equivalente, que também permite um espaço opcional: ([a-zA-Z] (?: (?: [A-zA- Z]? \ D [a-zA-Z]) | (?: \ D {1,2}) | (?: [A-zA-Z] \ d {1,2})) \ W? [0 -9] [a-zA-Z] {2})
Richard J
14

A maioria das respostas aqui não funcionou para todos os códigos postais que tenho no meu banco de dados. Finalmente encontrei um que valida com todos, usando o novo regex fornecido pelo governo:

https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/413338/Bulk_Data_Transfer_-_additional_validation_valid_from_March_2015.pdf

Não está em nenhuma das respostas anteriores, então eu o publico aqui, caso eles cancelem o link:

^([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})$

UPDATE: Regex atualizado conforme indicado por Jamie Bull. Não tenho certeza se foi meu erro ao copiar ou se houve um erro na regex do governo, o link está desativado agora ...

ATUALIZAÇÃO: Como as ctwheels encontraram, esse regex funciona com o sabor de javascript regex. Veja o comentário dele para um que funcione com o sabor pcre (php).

Jesús Carrera
fonte
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})$deve ser ^([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})$- detectar a diferença ;-)
Jamie Touro
1
Spot on! Atualizei minha resposta. Obrigado!
Jesús Carrera
2
Esta é a única resposta aqui que funcionou no regexr.com e no Notepad ++. No entanto, eu mudei para ([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})(removido ^e $adicionei um ?espaço após) para o regexr.com encontrar mais de um resultado e para os dois encontrarem um resultado que não tenha um separador de espaço.
Mythofechelon
@ctwheels Este regex é para o sabor javascript. Se o seu link com falha você selecionar javascript, ele funcionará. Esse é um ótimo problema e eu atualizarei minha resposta.
Jesús Carrera
1
O regex publicado na documentação é inerentemente incorreto. A expressão inteira deve ser agrupada em um grupo não captador (?:)e, em seguida, âncoras colocadas em torno dele. Veja isso falhar aqui . Para mais informações, veja minha resposta aqui . ^(?:([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}))$é a expressão regular corrigida.
Ctwheels
12

Um post antigo, mas ainda bastante alto nos resultados do google, pensei em atualizar. Este documento de 14 de outubro define a expressão regular do código postal do Reino Unido como:

^([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})|(([**AZ**a-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})$

de:

https://www.gov.uk/government/uploads/system/uploads/attachment_data/file/359448/4__Bulk_Data_Transfer_-_additional_validation_valid.pdf

O documento também explica a lógica por trás dele. No entanto, ele possui um erro (em negrito) e também permite letras minúsculas, o que, embora legal não seja usual, versão alterada:

^(GIR 0AA)|((([A-Z][0-9]{1,2})|(([A-Z][A-HJ-Y][0-9]{1,2})|(([A-Z][0-9][A-Z])|([A-Z][A-HJ-Y][0-9]?[A-Z])))) [0-9][A-Z]{2})$

Isso funciona com novos códigos postais de Londres (por exemplo, W1D 5LH) que versões anteriores não.

caranguejo morto
fonte
Parece que o erro destacado em negrito foi corrigido no documento, mas ainda assim prefiro sua expressão regular, pois é mais fácil de ler.
Professor de programação
5
A única coisa que eu diria é tornar o espaço opcional, alterando o espaço para \ s? como o espaço não é um requisito para legibilidade.
Professor de programação
O regex publicado na documentação é inerentemente incorreto. A expressão inteira deve ser agrupada em um grupo não captador (?:)e, em seguida, âncoras colocadas em torno dele. Veja isso falhar aqui . Para mais informações, veja minha resposta aqui . ^(?:([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}))$é a expressão regular corrigida.
Ctwheels
10

Este é o regex que o Google exibe no domínio i18napis.appspot.com :

GIR[ ]?0AA|((AB|AL|B|BA|BB|BD|BH|BL|BN|BR|BS|BT|BX|CA|CB|CF|CH|CM|CO|CR|CT|CV|CW|DA|DD|DE|DG|DH|DL|DN|DT|DY|E|EC|EH|EN|EX|FK|FY|G|GL|GY|GU|HA|HD|HG|HP|HR|HS|HU|HX|IG|IM|IP|IV|JE|KA|KT|KW|KY|L|LA|LD|LE|LL|LN|LS|LU|M|ME|MK|ML|N|NE|NG|NN|NP|NR|NW|OL|OX|PA|PE|PH|PL|PO|PR|RG|RH|RM|S|SA|SE|SG|SK|SL|SM|SN|SO|SP|SR|SS|ST|SW|SY|TA|TD|TF|TN|TQ|TR|TS|TW|UB|W|WA|WC|WD|WF|WN|WR|WS|WV|YO|ZE)(\d[\dA-Z]?[ ]?\d[ABD-HJLN-UW-Z]{2}))|BFPO[ ]?\d{1,4}
Alix Axel
fonte
10

Os códigos postais estão sujeitos a alterações, e a única maneira verdadeira de validar um código postal é ter a lista completa de códigos postais e ver se está lá.

Mas expressões regulares são úteis porque:

  • são fáceis de usar e implementar
  • são curtos
  • são rápidos de executar
  • são muito fáceis de manter (em comparação com uma lista completa de códigos postais)
  • ainda captura a maioria dos erros de entrada

Mas expressões regulares tendem a ser difíceis de manter, especialmente para alguém que não a apresentou em primeiro lugar. Então deve ser:

  • tão fácil de entender quanto possível
  • prova relativamente futura

Isso significa que a maioria das expressões regulares nesta resposta não é boa o suficiente. Por exemplo, eu posso ver que [A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y]isso corresponderá a uma área de código postal no formato AA1A - mas será uma dor de garganta se e quando uma nova área de código postal for adicionada, porque é difícil entender quais áreas de código postal correspondem.

Também quero que minha expressão regular corresponda à primeira e à segunda metade do código postal como correspondências entre parênteses.

Então, eu vim com isso:

(GIR(?=\s*0AA)|(?:[BEGLMNSW]|[A-Z]{2})[0-9](?:[0-9]|(?<=N1|E1|SE1|SW1|W1|NW1|EC[0-9]|WC[0-9])[A-HJ-NP-Z])?)\s*([0-9][ABD-HJLNP-UW-Z]{2})

No formato PCRE, pode ser escrito da seguinte forma:

/^
  ( GIR(?=\s*0AA) # Match the special postcode "GIR 0AA"
    |
    (?:
      [BEGLMNSW] | # There are 8 single-letter postcode areas
      [A-Z]{2}     # All other postcode areas have two letters
      )
    [0-9] # There is always at least one number after the postcode area
    (?:
      [0-9] # And an optional extra number
      |
      # Only certain postcode areas can have an extra letter after the number
      (?<=N1|E1|SE1|SW1|W1|NW1|EC[0-9]|WC[0-9])
      [A-HJ-NP-Z] # Possible letters here may change, but [IO] will never be used
      )?
    )
  \s*
  ([0-9][ABD-HJLNP-UW-Z]{2}) # The last two letters cannot be [CIKMOV]
$/x

Para mim, esse é o equilíbrio certo entre validar o máximo possível e, ao mesmo tempo, proteger o futuro e facilitar a manutenção.

andre
fonte
Não sei por que você foi rejeitado - isso funciona com todos os códigos postais válidos que eu joguei nele e espaços com os quais muitas das respostas acima não lidam corretamente. Alguém se importaria de explicar o porquê?
Jon
1
@ Jon Ele também corresponde quando outros caracteres são anexados ao início ou fim por exemplo aSW1A 1AAasfgcombinados para mim (eu não downvote embora como parece que poderia ser corrigido facilmente)
decvalts
9

Eu estive procurando um regex de código postal do Reino Unido nos últimos dias, e me deparei com esse tópico. Eu trabalhei na maioria das sugestões acima e nenhuma delas funcionou para mim. Por isso, criei meu próprio regex que, tanto quanto eu sei, captura todos os códigos postais válidos do Reino Unido a partir de janeiro de 13 (de acordo com a literatura mais recente do Royal Mail).

O regex e algum código postal simples para verificar o código PHP estão publicados abaixo. NOTA: - Permite códigos postais em maiúsculas ou minúsculas e a anomalia do GIR 0AA, mas, para lidar com a presença, mais do que provável, de um espaço no meio de um código postal inserido, ele também usa um simples str_replace para remover o espaço antes do teste contra a regex. Quaisquer discrepâncias além disso e o próprio Royal Mail nem sequer as mencionam em sua literatura (consulte http://www.royalmail.com/sites/default/files/docs/pdf/programmers_guide_edition_7_v5.pdf e comece a ler na página 17) !

Nota: Na literatura do Royal Mail (link acima), há uma pequena ambiguidade em torno da 3ª e 4ª posições e as exceções em vigor se esses caracteres forem letras. Entrei em contato diretamente com o Royal Mail para esclarecê-lo e com suas próprias palavras "Uma carta na 4ª posição do Código de Saída com o formato AANA NAA não tem exceções e as exceções da 3ª posição se aplicam apenas à última letra do Código de Saída com o formato ANA NAA ". Direto da boca do cavalo!

<?php

    $postcoderegex = '/^([g][i][r][0][a][a])$|^((([a-pr-uwyz]{1}([0]|[1-9]\d?))|([a-pr-uwyz]{1}[a-hk-y]{1}([0]|[1-9]\d?))|([a-pr-uwyz]{1}[1-9][a-hjkps-uw]{1})|([a-pr-uwyz]{1}[a-hk-y]{1}[1-9][a-z]{1}))(\d[abd-hjlnp-uw-z]{2})?)$/i';

    $postcode2check = str_replace(' ','',$postcode2check);

    if (preg_match($postcoderegex, $postcode2check)) {

        echo "$postcode2check is a valid postcode<br>";

    } else {

        echo "$postcode2check is not a valid postcode<br>";

    }

?>

Espero que ajude qualquer pessoa que encontre esse tópico à procura de uma solução.

Dan Solo
fonte
1
Eu ficaria curioso para saber quais códigos postais de exemplo estavam falhando no publicado?
Zhaph - Ben Duguid 12/01
Não posso fornecer um código postal específico (sem ter acesso à lista completa do PAF), mas os códigos postais com o formato ANA NAA poderiam falhar, pois as letras P e Q são permitidas na 3ª posição e os códigos postais com o formato AANA NAA também falham, pois a quarta posição permite todas as letras (a expressão regular dada na resposta aceita acima não é responsável por nenhuma dessas). Como eu digo, só estou seguindo os conselhos atuais do Royal Mail - no momento da resposta acima, talvez esse regex fosse totalmente compatível.
Dan Solo
Obrigado pelo alerta - posso ver que "P" parece ter sido adicionado como aceitável na terceira posição (do seu documento vinculado), mas não Q - mas onde você está lendo que "a quarta posição permite todas as letras"? O documento não menciona a "quarta posição", tanto quanto eu posso ver, então eu li isso como "a terceira letra, independentemente da posição real".
Zhaph - Ben Duguid
1
Acabei de receber uma mensagem da equipe de suporte do Royal Mail e minha interpretação das regras está correta, aparentemente. Uma letra na 4ª posição do Código Externo (por exemplo, AANA NAA) não tem exceções e as exceções da 3ª posição se aplicam apenas à última letra (por exemplo, ANA NAA). Direto da boca do cavalo.
Dan Solo
1
@DanSolo Este regex retornará uma correspondência verdadeira para a primeira metade de um código postal válido, sem o código interno, por exemplo SW1A ou BD25sem a segunda metade (ou pelo menos o fez para mim)
decvalts
7

Aqui está uma regex baseada no formato especificado nos documentos que estão vinculados à resposta de marcj:

/^[A-Z]{1,2}[0-9][0-9A-Z]? ?[0-9][A-Z]{2}$/

A única diferença entre isso e as especificações é que os dois últimos caracteres não podem estar em [CIKMOV] de acordo com as especificações.

Edit: Aqui está outra versão que testa as limitações de caracteres à direita.

/^[A-Z]{1,2}[0-9][0-9A-Z]? ?[0-9][A-BD-HJLNP-UW-Z]{2}$/
Will Tomlins
fonte
Há muito mais complexidades em um código postal do Reino Unido do que apenas aceitar A-Z- Qnunca é permitido, Vé usado apenas com moderação etc., dependendo da posição do personagem.
Zhaph # Ben Duguid
2
Isso talvez seja irrelevante se o que você deseja é uma verificação de sintaxe. Como muitos outros observaram, apenas uma pesquisa em um banco de dados atualizado fica quase correta e, mesmo assim, há o problema de como o banco de dados está atualizado. Portanto, para mim, esse regex do verificador de sintaxe é claro, simples e útil.
Rick-777
5

Algumas das regexs acima são um pouco restritivas. Observe o código postal genuíno: "W1K 7AA" falharia, dada a regra "Posição 3 - AEHMNPRTVXY usada apenas" acima, pois "K" seria proibido.

o regex:

^(GIR 0AA|[A-PR-UWYZ]([0-9]{1,2}|([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|[0-9][A-HJKPS-UW])[0-9][ABD-HJLNP-UW-Z]{2})$

Parece um pouco mais preciso, consulte o artigo da Wikipedia intitulado 'Códigos postais no Reino Unido' .

Observe que esse regex requer apenas caracteres maiúsculos.

A questão maior é se você está restringindo a entrada do usuário para permitir apenas códigos postais que realmente existem ou se você está simplesmente tentando impedir que os usuários digitem lixo completo nos campos do formulário. Combinar corretamente todos os códigos postais possíveis e protegê-los no futuro é um quebra-cabeça mais difícil e provavelmente não vale a pena, a menos que você seja o HMRC.

minglis
fonte
Parece que os correios seguiram em frente, mas o governo está um pouco atrasado :(
Zhaph - Ben Duguid
4
Eu uso este: "^ ([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,1} [0-9] [ A-Za-z] {2}) $ "Gosto porque permite maiúsculas e minúsculas e torna o espaço opcional - melhor para a usabilidade, se não estiver 100% correto!
BIGTV
4

veja como lidamos com a questão do código postal do Reino Unido:

^([A-Za-z]{1,2}[0-9]{1,2}[A-Za-z]?[ ]?)([0-9]{1}[A-Za-z]{2})$

Explicação:

  • espere 1 ou 2 caracteres de az, multa superior ou inferior
  • espere 1 ou 2 números
  • esperar 0 ou 1 az char, superior ou inferior fino
  • espaço opcional permitido
  • espera 1 número
  • esperar 2 az, multa superior ou inferior

Isso obtém a maioria dos formatos e, em seguida, usamos o db para validar se o código postal é realmente real, esses dados são conduzidos pelo ponto aberto https://www.ordnancesurvey.co.uk/opendatadownload/products.html

espero que isto ajude

Alex Stephens
fonte
Isso permite o formato AANNA NAAinválido.
Ctwheels #
Portanto, a parte "Isso obtém a maioria dos formatos" da resposta. :)
Alex Stephens
4

Regras básicas:

^[A-Z]{1,2}[0-9R][0-9A-Z]? [0-9][ABD-HJLNP-UW-Z]{2}$

Os códigos postais no Reino Unido (ou códigos postais, como são chamados) são compostos de cinco a sete caracteres alfanuméricos separados por um espaço. As regras que cobrem quais personagens podem aparecer em posições específicas são bastante complicadas e repletas de exceções. A expressão regular mostrada, portanto, segue as regras básicas.

Regras completas:

Se você precisar de uma regex que marque todas as caixas para as regras de código postal em detrimento da legibilidade, aqui está:

^(?:(?:[A-PR-UWYZ][0-9]{1,2}|[A-PR-UWYZ][A-HK-Y][0-9]{1,2}|[A-PR-UWYZ][0-9][A-HJKSTUW]|[A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y]) [0-9][ABD-HJLNP-UW-Z]{2}|GIR 0AA)$

Fonte: https://www.safaribooksonline.com/library/view/regular-expressions-cookbook/9781449327453/ch04s16.html

Testado no banco de dados de nossos clientes e parece perfeitamente preciso.

Raphos
fonte
4

Eu uso o seguinte regex que testei em todos os códigos postais válidos do Reino Unido. Ele é baseado nas regras recomendadas, mas é condensado o mais razoável e não faz uso de nenhuma regra regex específica do idioma.

([A-PR-UWYZ]([A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y])?|[0-9]([0-9]|[A-HJKPSTUW])?) ?[0-9][ABD-HJLNP-UW-Z]{2})

Ele pressupõe que o código postal foi convertido em maiúsculas e não possui caracteres iniciais ou finais, mas aceitará um espaço opcional entre o código externo e a codificação.

O código postal especial "GIR0 0AA" foi excluído e não será validado, pois não está na lista oficial de correios e, tanto quanto sei, não será usado como endereço registrado. Adicioná-lo deve ser trivial como um caso especial, se necessário.

Formão
fonte
4

Eu queria um regex simples, onde é bom permitir muito, mas não negar um código postal válido. Fui com isso (a entrada é uma seqüência de caracteres despojada / aparada):

/^([a-z0-9]\s*){5,8}$/i

Isso permite os códigos postais mais curtos possíveis, como "L1 8JQ", e os mais longos possíveis, como "OL14 5ET".

Como ele permite até 8 caracteres, também permitirá códigos postais com 8 caracteres incorretos se não houver espaço: "OL145ETX". Mas, novamente, este é um regex simplista, para quando isso for bom o suficiente.

Henrik N
fonte
Oh, minhas desculpas. Acho que perdi o / i quando estava testando ontem.
John
3

Primeira metade do código postal Formatos válidos

  • [AZ] [AZ] [0-9] [AZ]
  • [AZ] [AZ] [0-9] [0-9]
  • [AZ] [0-9] [0-9]
  • [AZ] [AZ] [0-9]
  • [AZ] [AZ] [AZ]
  • [AZ] [0-9] [AZ]
  • [AZ] [0-9]

Exceções
Posição 1 - QVX não usada
Posição 2 - IJZ não usada, exceto em GIR 0AA
Posição 3 - AEHMNPRTVXY usou apenas a
Posição 4 - ABEHMNPRVWXY

Segunda metade do código postal

  • [0-9] [AZ] [AZ]

Exceções
posição 2 + 3 - CIKMOV não usado

Lembre-se de que nem todos os códigos possíveis são usados; portanto, esta lista é uma condição necessária, mas não suficiente, para um código válido. Pode ser mais fácil corresponder apenas a uma lista de todos os códigos válidos?

Martin Beckett
fonte
3

Para verificar se um código postal está em um formato válido, de acordo com o guia do programador do Royal Mail :

          |----------------------------outward code------------------------------| |------inward code-----|
#special↓       α1        α2    AAN  AANA      AANN      AN    ANN    ANA (α3)        N         AA
^(GIR 0AA|[A-PR-UWYZ]([A-HK-Y]([0-9][A-Z]?|[1-9][0-9])|[1-9]([0-9]|[A-HJKPSTUW])?) [0-9][ABD-HJLNP-UW-Z]{2})$

Todos os códigos postais do doogal.co.uk correspondem, exceto aqueles que não estão mais em uso.

Adicionando um ?após o espaço e usando correspondência sem distinção entre maiúsculas e minúsculas para responder a esta pergunta:

'se50eg'.match(/^(GIR 0AA|[A-PR-UWYZ]([A-HK-Y]([0-9][A-Z]?|[1-9][0-9])|[1-9]([0-9]|[A-HJKPSTUW])?) ?[0-9][ABD-HJLNP-UW-Z]{2})$/ig);
Array [ "se50eg" ]
Jackson Pauls
fonte
3

Este permite espaços vazios e tabulações de ambos os lados, caso você não queira falhar na validação e, em seguida, apare-o.

^\s*(([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,1}[0-9][A-Za-z]{2})\s*$)
Matas Vaitkevicius
fonte
Este é o único padrão que funcionou para mim usando c # (System.Text.RegularExpressions) com os exemplos descritos na pergunta original
MattjeS
Este é o regex quebrado do governo do Reino Unido e não consegue validar alguns dos formatos válidos.
ctwheels
Olá, você poderia fornecer um código postal com falha, obrigado.
Matas Vaitkevicius
Por exemplo, AAA 1AAnão é um formato válido: veja minha resposta para obter uma explicação e correção.
ctwheels
2

Para adicionar a esta lista um regex mais prático que eu uso que permite ao usuário inserir um empty stringé:

^$|^(([gG][iI][rR] {0,}0[aA]{2})|((([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y]?[0-9][0-9]?)|(([a-pr-uwyzA-PR-UWYZ][0-9][a-hjkstuwA-HJKSTUW])|([a-pr-uwyzA-PR-UWYZ][a-hk-yA-HK-Y][0-9][abehmnprv-yABEHMNPRV-Y]))) {0,1}[0-9][abd-hjlnp-uw-zABD-HJLNP-UW-Z]{2}))$

Esse regex permite letras maiúsculas e minúsculas com um espaço opcional entre

Do ponto de vista dos desenvolvedores de software, esse regex é útil para softwares em que um endereço pode ser opcional. Por exemplo, se um usuário não quis fornecer seus detalhes de endereço

user1
fonte
1

Dê uma olhada no código python nesta página:

http://www.brunningonline.net/simon/blog/archives/001292.html

Eu tenho algum código postal para analisar. O requisito é bem simples; Eu tenho que analisar um código postal em um código externo e (opcional) incode. A boa notícia é que não preciso realizar nenhuma validação - só preciso detalhar o que me foi fornecido de uma maneira vagamente inteligente. Não posso assumir muita coisa sobre minha importação em termos de formatação, ou seja, maiúsculas e minúsculas e espaços incorporados. Mas estas não são as más notícias; a má notícia é que eu tenho que fazer tudo isso em RPG. :-(

No entanto, juntei uma pequena função Python para esclarecer meu pensamento.

Eu usei para processar códigos postais para mim.

Rudiger Wolf
fonte
1

Nos foi dada uma especificação:

Os códigos postais do Reino Unido devem estar em uma das seguintes formas (com uma exceção, veja abaixo): 
    § A9 9AA 
    § A99 9AA
    § AA9 9AA
    § AA99 9AA
    § A9A 9AA
    § AA9A 9AA
onde A representa um caractere alfabético e 9 representa um caractere numérico.
Regras adicionais se aplicam a caracteres alfabéticos, como a seguir:
    § O caractere na posição 1 não pode ser Q, V ou X
    § O personagem na posição 2 não pode ser I, J ou Z
    § O caractere na posição 3 não pode ser I, L, M, N, O, P, Q, R, V, X, Y ou Z
    § O caractere na posição 4 não pode ser C, D, F, G, I, J, K, L, O, Q, S, T, U ou Z
    § Os caracteres nas duas posições mais à direita não podem ser C, I, K, M, O ou V
A única exceção que não segue essas regras gerais é o código postal "GIR 0AA", que é um código postal válido válido.

Chegamos a isso:

/^([A-PR-UWYZ][A-HK-Y0-9](?:[A-HJKS-UW0-9][ABEHMNPRV-Y0-9]?)?\s*[0-9][ABD-HJLNP-UW-Z]{2}|GIR\s*0AA)$/i

Mas observe - isso permite qualquer número de espaços entre os grupos.

paulslater19
fonte
2
paulslater19, infelizmente sua solução permite códigos postais A99A 9AA.
1

Eu tenho o regex para validação de código postal do Reino Unido.

Isso funciona para todo o tipo de código postal interno ou externo

^((([A-PR-UWYZ][0-9])|([A-PR-UWYZ][0-9][0-9])|([A-PR-UWYZ][A-HK-Y][0-9])|([A-PR-UWYZ][A-HK-Y][0-9][0-9])|([A-PR-UWYZ][0-9][A-HJKSTUW])|([A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRVWXY]))) || ^((GIR)[ ]?(0AA))$|^(([A-PR-UWYZ][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][0-9][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][A-HK-Y0-9][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][A-HK-Y0-9][0-9][0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][0-9][A-HJKS-UW0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$|^(([A-PR-UWYZ][A-HK-Y0-9][0-9][ABEHMNPRVWXY0-9])[ ]?([0-9][ABD-HJLNPQ-UW-Z]{0,2}))$

Isso está funcionando para todos os tipos de formato.

Exemplo:

AB10 --------------------> SOMENTE POSTAIS EXTERNOS

A1 1AA ------------------> Combinação de cartão postal (externo e interno)

WC2A --------------------> EXTERIOR

Swift-Master
fonte
1

A resposta aceita reflete as regras dadas pelo Royal Mail, embora haja um erro de digitação no regex. Esse erro de digitação parece estar lá também no site gov.uk (como na página de arquivo XML).

No formato A9A 9AA, as regras permitem um caractere P na terceira posição, enquanto a regex não o permite. O regex correto seria:

(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-HJKPSTUW])|([A-Z-[QVX]][A-Z-[IJZ]][0-9][ABEHMNPRVWXY])))) [0-9][A-Z-[CIKMOV]]{2}) 

Encurtar isso resulta na seguinte expressão regular (que usa a sintaxe Perl / Ruby):

(GIR 0AA)|([A-PR-UWYZ](([0-9]([0-9A-HJKPSTUW])?)|([A-HK-Y][0-9]([0-9ABEHMNPRVWXY])?))\s?[0-9][ABD-HJLNP-UW-Z]{2})

Também inclui um espaço opcional entre o primeiro e o segundo bloco.

Stieb
fonte
1

O que encontrei em quase todas as variações e o regex do pdf de transferência em massa e o que está no site wikipedia é este, especificamente para o regex wikipedia, é necessário que haja um ^ após o primeiro | (barra vertical). Eu descobri isso testando o AA9A 9AA, porque, caso contrário, a verificação de formato do A9A 9AA o validará. Por exemplo, a verificação de EC1D 1BB que deve ser inválida volta válida porque C1D 1BB é um formato válido.

Aqui está o que eu criei para uma boa regex:

^([G][I][R] 0[A]{2})|^((([A-Z-[QVX]][0-9]{1,2})|([A-Z-[QVX]][A-HK-Y][0-9]{1,2})|([A-Z-[QVX]][0-9][ABCDEFGHJKPSTUW])|([A-Z-[QVX]][A-HK-Y][0-9][ABEHMNPRVWXY])) [0-9][A-Z-[CIKMOV]]{2})$
Andrew Schliewe
fonte
1

Através de testes empíricos e observação, além de confirmar com https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation , aqui está minha versão de um regex Python que analisa e valida corretamente um código postal do Reino Unido:

UK_POSTCODE_REGEX = r'(?P<postcode_area>[A-Z]{1,2})(?P<district>(?:[0-9]{1,2})|(?:[0-9][A-Z]))(?P<sector>[0-9])(?P<postcode>[A-Z]{2})'

Essa regex é simples e possui grupos de captura. Ele não inclui todas as validações de códigos postais legais do Reino Unido, mas leva em consideração apenas as posições das letras versus números.

Aqui está como eu o usaria no código:

@dataclass
class UKPostcode:
    postcode_area: str
    district: str
    sector: int
    postcode: str

    # https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation
    # Original author of this regex: @jontsai
    # NOTE TO FUTURE DEVELOPER:
    # Verified through empirical testing and observation, as well as confirming with the Wiki article
    # If this regex fails to capture all valid UK postcodes, then I apologize, for I am only human.
    UK_POSTCODE_REGEX = r'(?P<postcode_area>[A-Z]{1,2})(?P<district>(?:[0-9]{1,2})|(?:[0-9][A-Z]))(?P<sector>[0-9])(?P<postcode>[A-Z]{2})'

    @classmethod
    def from_postcode(cls, postcode):
        """Parses a string into a UKPostcode

        Returns a UKPostcode or None
        """
        m = re.match(cls.UK_POSTCODE_REGEX, postcode.replace(' ', ''))

        if m:
            uk_postcode = UKPostcode(
                postcode_area=m.group('postcode_area'),
                district=m.group('district'),
                sector=m.group('sector'),
                postcode=m.group('postcode')
            )
        else:
            uk_postcode = None

        return uk_postcode


def parse_uk_postcode(postcode):
    """Wrapper for UKPostcode.from_postcode
    """
    uk_postcode = UKPostcode.from_postcode(postcode)
    return uk_postcode

Aqui estão os testes de unidade:

@pytest.mark.parametrize(
    'postcode, expected', [
        # https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation
        (
            'EC1A1BB',
            UKPostcode(
                postcode_area='EC',
                district='1A',
                sector='1',
                postcode='BB'
            ),
        ),
        (
            'W1A0AX',
            UKPostcode(
                postcode_area='W',
                district='1A',
                sector='0',
                postcode='AX'
            ),
        ),
        (
            'M11AE',
            UKPostcode(
                postcode_area='M',
                district='1',
                sector='1',
                postcode='AE'
            ),
        ),
        (
            'B338TH',
            UKPostcode(
                postcode_area='B',
                district='33',
                sector='8',
                postcode='TH'
            )
        ),
        (
            'CR26XH',
            UKPostcode(
                postcode_area='CR',
                district='2',
                sector='6',
                postcode='XH'
            )
        ),
        (
            'DN551PT',
            UKPostcode(
                postcode_area='DN',
                district='55',
                sector='1',
                postcode='PT'
            )
        )
    ]
)
def test_parse_uk_postcode(postcode, expected):
    uk_postcode = parse_uk_postcode(postcode)
    assert(uk_postcode == expected)
jontsai
fonte
0

Eu precisava de uma versão que funcionasse no SAS com as PRXMATCHfunções e relacionadas, então eu vim com isso:

^[A-PR-UWYZ](([A-HK-Y]?\d\d?)|(\d[A-HJKPSTUW])|([A-HK-Y]\d[ABEHMNPRV-Y]))\s?\d[ABD-HJLNP-UW-Z]{2}$

Casos de teste e notas:

/* 
Notes
The letters QVX are not used in the 1st position.
The letters IJZ are not used in the second position.
The only letters to appear in the third position are ABCDEFGHJKPSTUW when the structure starts with A9A.
The only letters to appear in the fourth position are ABEHMNPRVWXY when the structure starts with AA9A.
The final two letters do not use the letters CIKMOV, so as not to resemble digits or each other when hand-written.
*/

/*
    Bits and pieces
    1st position (any):         [A-PR-UWYZ]         
    2nd position (if letter):   [A-HK-Y]
    3rd position (A1A format):  [A-HJKPSTUW]
    4th position (AA1A format): [ABEHMNPRV-Y]
    Last 2 positions:           [ABD-HJLNP-UW-Z]    
*/


data example;
infile cards truncover;
input valid 1. postcode &$10. Notes &$100.;
flag = prxmatch('/^[A-PR-UWYZ](([A-HK-Y]?\d\d?)|(\d[A-HJKPSTUW])|([A-HK-Y]\d[ABEHMNPRV-Y]))\s?\d[ABD-HJLNP-UW-Z]{2}$/',strip(postcode));
cards;
1  EC1A 1BB  Special case 1
1  W1A 0AX   Special case 2
1  M1 1AE    Standard format
1  B33 8TH   Standard format
1  CR2 6XH   Standard format
1  DN55 1PT  Standard format
0  QN55 1PT  Bad letter in 1st position
0  DI55 1PT  Bad letter in 2nd position
0  W1Z 0AX   Bad letter in 3rd position
0  EC1Z 1BB  Bad letter in 4th position
0  DN55 1CT  Bad letter in 2nd group
0  A11A 1AA  Invalid digits in 1st group
0  AA11A 1AA  1st group too long
0  AA11 1AAA  2nd group too long
0  AA11 1AAA  2nd group too long
0  AAA 1AA   No digit in 1st group
0  AA 1AA    No digit in 1st group
0  A 1AA     No digit in 1st group
0  1A 1AA    Missing letter in 1st group
0  1 1AA     Missing letter in 1st group
0  11 1AA    Missing letter in 1st group
0  AA1 1A    Missing letter in 2nd group
0  AA1 1     Missing letter in 2nd group
;
run;
user667489
fonte
0

O método abaixo verificará o código postal e fornecerá informações completas

const valid_postcode = postcode => {
    try {
        postcode = postcode.replace(/\s/g, "");
        const fromat = postcode
            .toUpperCase()
            .match(/^([A-Z]{1,2}\d{1,2}[A-Z]?)\s*(\d[A-Z]{2})$/);
        const finalValue = `${fromat[1]} ${fromat[2]}`;
        const regex = /^([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})$/i;
        return {
            isValid: regex.test(postcode),
            formatedPostCode: finalValue,
            error: false,
            info: 'It is a valid postcode'
        };
    } catch (error) {
        return { error: true , info: 'Invalid post code has been entered!'};
    }
};
valid_postcode('GU348RR')
result => {isValid: true, formatedPostCode: "GU34 8RR", error: false, info: "It is a valid postcode"}
valid_postcode('sdasd4746asd')
result => {error: true, info: "Invalid post code has been entered!"}
valid_postcode('787898523')
result => {error: true, info: "Invalid post code has been entered!"}
Aathi
fonte