RegEx para hacer coincidir los códigos postales del Reino Unido


186

Estoy detrás de una expresión regular que validará un código postal complejo completo del Reino Unido solo dentro de una cadena de entrada. Todos los formularios de códigos postales poco comunes deben estar cubiertos, así como lo habitual. Por ejemplo:

Partidos

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

Sin coincidencia

  • aWC2H 7LT
  • WC2H 7LTa
  • WC2H

¿Cómo resuelvo este problema?


2
@axrwkr que no parece útil
Kieran Benton

8
Validación de código postal del Reino Unido: JavaScript y PHP No pude obtener la respuesta aceptada para que coincida con códigos postales válidos, pero encontré esto y coincide con códigos postales válidos. Para la validación del lado del cliente, la versión de JavaScript se puede usar tal cual, para la validación del lado del servidor, reescribir el JavaScript como C # es bastante sencillo. Incluso formatea el código postal para tener un espacio, por lo que si ingresa un código postal como W1A1AA, además de validarlo, lo formateará a W1A 1AA. Incluso se ocupa de códigos postales inusuales en varios territorios británicos.

2
El enlace proporcionado no funciona para los formatos "AA1A 1AA". Referencia: dhl.com.tw/content/dam/downloads/tw/express/forms/…
Anthony Scaife

1
Si simplemente desea validar un código postal, ofrecemos un punto final de API REST de validación gratuito (requiere registro) - developers.alliescomputing.com/postcoder-web-api/address-lookup/…
Stephen Keable

1
Buena pregunta. Creo que valdría la pena incluir códigos postales centrales de Manchester como "M1 3HZ" en su lista de ejemplos poco comunes que deben coincidir. Muchas personas no son conscientes de los combos de 1 letra 1 número.
Martin Joiner

Respuestas:


208

Recomiendo echar un vistazo al Estándar de datos del gobierno del Reino Unido para códigos postales [enlace ahora muerto; archivo de XML , ver Wikipedia para discusión]. Hay una breve descripción sobre los datos y el esquema xml adjunto proporciona una expresión regular. Puede que no sea exactamente lo que desea, pero sería un buen punto de partida. El RegEx difiere ligeramente del XML, ya que la definición dada permite un carácter P en la tercera posición en formato A9A 9AA.

El RegEx suministrado por el Gobierno del Reino Unido fue:

([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 se señaló en la discusión de Wikipedia, esto permitirá algunos códigos postales no reales (por ejemplo, aquellos que comienzan AA, ZY) y proporcionan una prueba más rigurosa que podría probar.


52
Y ese reg ex con un espacio en blanco opcional entre los dos 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

77
Podría ser una buena idea para llevar la expresión regular real para la respuesta, ya que las páginas se parecen a punto de expirar cada año ...
pauloya

77
Tenga en cuenta que esta expresión regular es para el esquema XML, que es, obviamente, ligeramente diferente de otros sabores de
expresiones

66
No puedo hacer que esto funcione en JavaScript. ¿Funciona solo con ciertos motores regex?
NickG

12
En realidad lo cambiaron: Transferencia de datos a granel :^([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 a 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 es una versión ligeramente modificada de la sugerida por Minglis arriba.

Sin embargo, vamos a tener que investigar exactamente cuáles son las reglas, ya que las diversas soluciones enumeradas anteriormente parecen aplicar diferentes reglas sobre qué letras están permitidas.

Después de algunas investigaciones, hemos encontrado más información. Aparentemente, una página en 'govtalk.gov.uk' lo señala a una especificación de código postal govtalk-postcodes . Esto apunta a un esquema XML en XML Schema que proporciona una declaración 'pseudo regex' de las reglas del código postal.

Tomamos eso y trabajamos un poco para darnos la siguiente expresión:

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

Esto hace que los espacios sean opcionales, pero lo limita a un espacio (reemplace '&' con '{0,} para espacios ilimitados). Se supone que todo el texto debe estar en mayúscula.

Si desea permitir minúsculas, con cualquier número de espacios, 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}))$

Esto no cubre territorios en el extranjero y solo impone el formato, NO la existencia de diferentes áreas. Se basa en las siguientes reglas:

Puede aceptar los siguientes formatos:

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

Dónde:

  • 9 puede ser cualquier número de un solo dígito.
  • A puede ser cualquier letra excepto Q, V o X.
  • B puede ser cualquier letra excepto I, J o Z.
  • C puede ser cualquier letra excepto I, L, M, N, O, P, Q, R, V, X, Y o Z.
  • D puede ser cualquier letra excepto I, J o Z.
  • E puede ser cualquiera de A, B, E, H, M, N, P, R, V, W, X o Y.
  • Z puede ser cualquier letra excepto C, I, K, M, O o V.

Los mejores deseos

Colin


2
Gran respuesta, agregué en los extranjeros^(([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 el

¿Por qué especificar en {0,}lugar de *espacios ilimitados y opcionales?
Código Animal

76

Recientemente he publicado una respuesta a esta pregunta en los códigos postales del Reino Unido para el lenguaje R . Descubrí que el patrón de expresiones regulares del gobierno del Reino Unido es incorrecto y no funciona correctamente valida algunos códigos postales. Desafortunadamente, muchas de las respuestas aquí se basan en este patrón incorrecto.

Esbozaré algunos de estos problemas a continuación y proporcionaré una expresión regular revisada que realmente funcione.


Nota

Mi respuesta (y expresiones regulares en general):

  • Solo valida formatos de código postal .
  • No garantiza que exista un código postal legítimamente .

Si no te importa la expresión regular incorrecta y solo quieres saltar a la respuesta, desplázate hacia abajo hasta la sección Respuesta .

The Bad Regex

Las expresiones regulares en esta sección no deben usarse.

Esta es la expresión regular fallida que el gobierno del Reino Unido ha proporcionado a los desarrolladores (no estoy seguro de cuánto tiempo estará activo este enlace, pero puede verlo en su documentación de Transferencia de datos a granel ):

^([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 / Pegar

Ver expresiones regulares en uso aquí .

Como muchos desarrolladores probablemente hacen, copian / pegan código (especialmente expresiones regulares) y los pegan esperando que funcionen. Si bien esto es excelente en teoría, falla en este caso particular porque la copia / pegado de este documento en realidad cambia uno de los caracteres (un espacio) a un carácter de nueva línea como se muestra a continuación:

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

Lo primero que harán la mayoría de los desarrolladores es borrar la nueva línea sin pensarlo dos veces. Ahora la expresión regular no coincidirá con los códigos postales con espacios en ellos (aparte delGIR 0AA código postal).

Para solucionar este problema, el carácter de nueva línea debe reemplazarse con el carácter de espacio:

^([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 - Límites

Ver expresiones regulares en uso aquí .

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

El código postal regex ancla incorrectamente el regex. Cualquiera que use esta expresión regular para validar códigos postales podría sorprenderse si un valor como fooA11 1AApasa. Eso es porque han anclado el inicio de la primera opción y el final de la segunda opción (independientemente uno del otro), como se señala en la expresión regular anterior.

Lo que esto significa es que ^(afirma la posición al comienzo de la línea) solo funciona en la primera opción ([Gg][Ii][Rr] 0[Aa]{2}), por lo que la segunda opción validará cualquier cadena que termine en un código postal (independientemente de lo que ocurra antes).

Del mismo modo, la primera opción no está anclada al final de la línea $, por GIR 0AAfoolo que también se acepta.

^([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 solucionar este problema, ambas opciones deben estar envueltas en otro grupo (o grupo que no sea de captura) y los anclajes colocados alrededor de eso:

^(([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: juego de caracteres incorrecto

Ver expresiones regulares en uso aquí .

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

Al regex le falta un -aquí para indicar un rango de caracteres. Tal como está, si un código postal está en el formato ANA NAA(donde Arepresenta una letra y Nrepresenta un número), y comienza con cualquier cosa que no sea AoZ , fallará.

Eso significa que coincidirá A1A 1AAy Z1A 1AA, pero no B1A 1AA.

Para solucionar este problema, el carácter se -debe colocar entre Ay Zen el conjunto de caracteres correspondiente:

^([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: juego de caracteres opcional incorrecto

Ver expresiones regulares en uso aquí .

^([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 ni siquiera probaron esto antes de publicitarlo en la web. Hicieron el juego de caracteres incorrecto opcional. Hicieron [0-9]opción en la cuarta subopción de la opción 2 (grupo 9). Esto permite que la expresión regular coincida con códigos postales con formato incorrecto comoAAA 1AA .

Para solucionar este problema, haga que la siguiente clase de caracteres sea opcional (y luego haga que el conjunto [0-9]coincida exactamente una 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 - Rendimiento

El rendimiento en esta expresión regular es extremadamente pobre. En primer lugar, colocaron la opción de patrón menos probable para que coincida GIR 0AAal principio. ¿Cuántos usuarios tendrán este código postal en comparación con cualquier otro código postal? ¿probablemente nunca? Esto significa que cada vez que se utiliza la expresión regular, debe agotar esta opción antes de pasar a la siguiente. Para ver cómo se ve afectado el rendimiento, verifique el número de pasos que tomó la expresión regular original (35) contra la misma expresión regular después de haber cambiado las opciones (22).

El segundo problema con el rendimiento se debe a la forma en que se estructura toda la expresión regular. No tiene sentido retroceder sobre cada opción si una falla. La forma en que se estructura la expresión regular actual se puede simplificar enormemente. Proporciono una solución para esto en la sección Respuesta .

Problema 6 - Espacios

Ver expresiones regulares en uso aquí

Esto puede no considerarse un problema , per se, pero genera preocupación para la mayoría de los desarrolladores. Los espacios en la expresión regular no son opcionales, lo que significa que los usuarios que ingresan sus códigos postales deben colocar un espacio en el código postal. Esta es una solución fácil simplemente agregando ?después de los espacios para hacerlos opcionales. Vea la sección de Respuesta para una solución.


Responder

1. Arreglando la expresión regular del gobierno del Reino Unido

Solucionar todos los problemas descritos en la sección Problemas y simplificar el patrón produce el siguiente patrón, más corto y conciso. También podemos eliminar la mayoría de los grupos ya que estamos validando el código postal en su conjunto (no partes individuales):

Ver expresiones regulares en uso aquí

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

Esto se puede acortar aún más eliminando todos los rangos de uno de los casos (mayúsculas o minúsculas) y utilizando una marca que no distinga entre mayúsculas y minúsculas. Nota : Algunos idiomas no tienen uno, así que use el más largo de arriba. Cada idioma implementa el distintivo de mayúsculas y minúsculas de manera diferente.

Ver expresiones regulares en uso aquí .

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

Más corto de nuevo reemplazando [0-9]con \d(si su motor regex lo admite):

Ver expresiones regulares en uso aquí .

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

2. Patrones simplificados

Sin garantizar caracteres alfabéticos específicos, se puede utilizar lo siguiente (tenga en cuenta las simplificaciones de 1. La fijación de la expresión regular del gobierno del Reino Unido también se ha aplicado aquí):

Ver expresiones regulares en uso aquí .

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

Y aún más si no te importa el caso especial GIR 0AA:

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

3. Patrones complicados

No sugeriría una verificación excesiva de un código postal, ya que pueden aparecer nuevas áreas, distritos y subdistritos en cualquier momento. Lo que sugeriré hacer potencialmente es agregar soporte para casos extremos. Existen algunos casos especiales y se describen en este artículo de Wikipedia .

Aquí hay expresiones regulares complejas que incluyen las subsecciones de 3. (3.1, 3.2, 3.3).

En relación con los patrones en 1. Arreglando la expresión regular del gobierno del Reino Unido :

Ver expresiones regulares en uso aquí

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

Y en relación con 2. Patrones simplificados :

Ver expresiones regulares en uso aquí

^(([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 Territorios británicos de ultramar

El artículo de Wikipedia actualmente declara (algunos formatos ligeramente simplificados):

  • AI-1111: Anguila
  • ASCN 1ZZ: Isla Ascencion
  • STHL 1ZZ: Santa Elena
  • TDCU 1ZZ: Tristan da Cunha
  • BBND 1ZZ: Territorio Británico del Océano Índico
  • BIQQ 1ZZ: Territorio Antártico Británico
  • FIQQ 1ZZ: Islas Malvinas
  • GX11 1ZZ: Gibraltar
  • PCRN 1ZZ: Islas Pitcairn
  • SIQQ 1ZZ: Georgia del sur y las islas Sandwich del sur
  • TKCA 1ZZ: Islas Turcas y Caicos
  • BFPO 11: Akrotiri y Dhekelia
  • ZZ 11& GE CX: Bermudas (según este documento )
  • KY1-1111: Islas Caimán (según este documento )
  • VG1111: Islas Vírgenes Británicas (según este documento )
  • MSR 1111: Montserrat (según este documento )

Una expresión regular que lo abarque todo y que solo coincida con los Territorios Británicos de Ultramar podría verse así:

Ver expresiones regulares en uso aquí .

^((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 Oficina de correos de las fuerzas británicas

Aunque se han cambiado recientemente para alinearse mejor con el sistema de código postal británico BF#(donde #representa un número), se consideran códigos postales alternativos opcionales . Estos códigos postales siguen (ed) el formato de BFPO, seguido de 1-4 dígitos:

Ver expresiones regulares en uso aquí

^BFPO ?\d{1,4}$

3.3 Santa?

Hay otro caso especial con Santa (como se menciona en otras respuestas): SAN TA1es un código postal válido. Una expresión regular para esto es muy simple:

^SAN ?TA1$

44
Los patrones simplificados son una muy buena opción para usar. Creo que es mejor no ser demasiado restrictivo con una expresión regular, ya que luego debe asegurarse de que se actualice con cualquier cambio o podría tener usuarios muy enojados. Creo que es mejor combinar libremente con una expresión regular simplificada para eliminar los errores obvios y luego aplicar controles adicionales como una búsqueda de dirección (o correo electrónico de confirmación en el caso de la expresión regular de correo electrónico) para confirmar la validez.
James Coyle

2
Excelente y minucioso análisis.
Steve

1
Respuesta brillante en muchos niveles. Finalmente, fui con tu segundo patrón simplificado. Como en realidad tengo una base de datos con todos los códigos postales del Reino Unido, solo necesito un primer paso para ver si una cadena de dirección potencialmente contiene un código postal válido, por lo que no me importan los falsos positivos (ya que la búsqueda real los eliminará) , pero me importan los falsos negativos. Y la velocidad también importa.
John Powell

Hay muchos problemas con el sistema de código postal del Reino Unido, creado manifiestamente por el comité antes de la era de las computadoras, pero el problema de la longitud y los espacios variables es uno de los más perniciosos. He visto todo tipo de horrores, incluidos los códigos postales de relleno como E1 5JX a E1 5JX, es decir, con tres espacios, de modo que se alinea muy bien con SW18 5HA en Excel (inserte el software horriblemente inapropiado de elección para administrar direcciones). La única solución sensata, en mi humilde opinión, es eliminar todos los espacios, de modo que el código postal sea una sola cadena antes de que se acerque a Elastic, Solr, Postgres, etc.
John Powell

45

No existe una expresión regular completa de código postal del Reino Unido que sea capaz de validar un código postal. Puede verificar que un código postal esté en el formato correcto utilizando una expresión regular; No es que realmente exista.

Los códigos postales son arbitrariamente complejos y cambian constantemente. Por ejemplo, el código de salida W1no tiene, y puede que nunca, tenga todos los números entre 1 y 99, para cada área de código postal.

No puedes esperar que lo que hay actualmente sea cierto para siempre. Como ejemplo, en 1990, la oficina de correos decidió que Aberdeen se estaba abarrotando un poco. Agregaron un 0 al final de AB1-5 convirtiéndolo en AB10-50 y luego crearon una serie de códigos postales entre estos.

Cada vez que se construye una nueva calle, se crea un nuevo código postal. Es parte del proceso para obtener permiso para construir; Las autoridades locales están obligadas a mantener esto actualizado con la oficina de correos (no es que todos lo hagan).

Además, como lo han señalado varios otros usuarios, existen códigos postales especiales como Girobank, GIR 0AA y el de cartas a Santa, SAN TA1: probablemente no desee publicar nada allí, pero parece que no estar cubierto por cualquier otra respuesta.

Luego, están los códigos postales BFPO, que ahora están cambiando a un formato más estándar . Ambos formatos serán válidos. Por último, está la fuente de los territorios de ultramar Wikipedia .

+ ---------- + -------------------------------------- -------- +
El | Código postal | Ubicación |
+ ---------- + -------------------------------------- -------- +
El | AI-2640 | Anguila |
El | ASCN 1ZZ | Isla Ascensión |
El | STHL 1ZZ | Santa Elena |
El | TDCU 1ZZ | Tristan da Cunha |
El | BBND 1ZZ | Territorio Británico del Océano Índico |
El | BIQQ 1ZZ | Territorio Antártico Británico |
El | FIQQ 1ZZ | Islas Malvinas |
El | GX11 1AA | Gibraltar |
El | PCRN 1ZZ | Islas Pitcairn |
El | SIQQ 1ZZ | Islas Georgias del Sur y Sandwich del Sur |
El | TKCA 1ZZ | Islas Turcas y Caicos |
+ ---------- + -------------------------------------- -------- +

A continuación, debe tener en cuenta que el Reino Unido "exportó" su sistema de código postal a muchos lugares del mundo. Cualquier cosa que valide un código postal del "Reino Unido" también validará los códigos postales de varios otros países.

Si desea validar un código postal del Reino Unido, la forma más segura de hacerlo es utilizar una búsqueda de códigos postales actuales. Hay muchas opciones:

  • Ordnance Survey lanza Code-Point Open bajo una licencia de datos abiertos. Será un poco atrasado pero es gratis. Esto (probablemente, no puedo recordar) no incluirá datos de Irlanda del Norte, ya que la Encuesta de Artillería no tiene ninguna misión allí. El mapeo en Irlanda del Norte se lleva a cabo por la Encuesta de artillería de Irlanda del Norte y tienen su producto Pointer separado y pagado . Puede usar esto y agregar los pocos que no están cubiertos con bastante facilidad.

  • Royal Mail lanza el archivo de dirección de código postal (PAF) , esto incluye BFPO, que no estoy seguro de que Code-Point Open lo haga. Se actualiza regularmente pero cuesta dinero (y a veces pueden ser francamente mezquinos al respecto). PAF incluye la dirección completa en lugar de solo códigos postales y viene con su propia Guía de programadores . El Open Data User Group (ODUG) está actualmente presionando para que se publique PAF de forma gratuita, aquí hay una descripción de su posición .

  • Por último, está AddressBase . Esta es una colaboración entre Ordnance Survey, las autoridades locales, Royal Mail y una compañía coincidente para crear un directorio definitivo de toda la información sobre todas las direcciones del Reino Unido (también han tenido bastante éxito). Está pagado, pero si está trabajando con una Autoridad Local, un departamento gubernamental o un servicio gubernamental, es gratis para ellos. Hay mucha más información que solo códigos postales incluidos.


la búsqueda suena interesante
SuperUberDuper

2
Si bien esta no es la respuesta que buscaba el operador, probablemente sea la más útil. Esto me animará a relajar las reglas de verificación que voy a hacer.
John Hunt

22

Eché un vistazo a algunas de las respuestas anteriores y recomendaría no usar el patrón de la respuesta de @ Dan (c. Dec 15 '10) , ya que marca incorrectamente casi el 0.4% de los códigos postales válidos como inválidos, mientras que los demás no lo hacen. .

Ordnance Survey proporciona un servicio llamado Code Point Open que:

contiene una lista de todas las unidades de código postal actuales en Gran Bretaña

Ejecuté cada una de las expresiones regulares anteriores con la lista completa de códigos postales (6 de julio de 13) a partir de estos datos 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"

Hay 1,686,202 códigos postales en total.

Los siguientes son los números de códigos postales válidos que no coinciden con cada uno $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

Por supuesto, estos resultados solo se refieren a códigos postales válidos que se marcan incorrectamente como no válidos. Entonces:

'^.*$'
# => 0

No digo nada sobre qué patrón es el mejor para filtrar códigos postales no válidos.


1
¿No es esto lo que digo en mi respuesta y si vas por la ruta de prueba probablemente deberías hacerlas todas y mantenerla actualizada si alguien cambia su respuesta? Si no, al menos haga referencia a la fecha de la última edición de la respuesta de la que la obtuvo para que las personas puedan ver si se ha cambiado desde entonces.
Ben

Punto justo. Editado en consecuencia. Creo que se agrega a la discusión para señalar que la mayoría de estos patrones no excluyen ninguno de los códigos CPO, pero que la respuesta más votada (expresión regular válida) sí lo hace. Futuros lectores: tenga en cuenta que mis resultados probablemente no estén actualizados.
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)$

Expresión regular para que coincida con códigos postales válidos del Reino Unido. En el sistema postal del Reino Unido, no todas las letras se utilizan en todas las posiciones (lo mismo con las placas de matrícula del vehículo) y hay varias reglas para regularlo. Esta expresión regular tiene en cuenta esas reglas. Detalles de las reglas: Primera mitad del 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] Excepciones Posición - Primero. Contraint - QVX no utilizado Posición - Segundo. Contraint - IJZ no se utiliza, excepto en la posición GIR 0AA - Tercero. Restricción: AEHMNPRTVXY solo utilizó Posición: adelante. Contraint - ABEHMNPRVWXY Segunda mitad del código postal Formatos válidos [0-9] [AZ] [AZ] Excepciones Posición - Segunda y tercera. Contraint - CIKMOV no utilizado

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


1
No tengo idea de por qué la gente ha rechazado esta respuesta: es la expresión regular correcta
Ollie

La expresión regular no funciona para los códigos postales "YO31" y "YO31 1" en Javscript.
Pratik Khadloya

9
No creo que esto sea correcto, ya que la expresión regular dada contradice la descripción y sugiere que puede tener códigos postales que comiencen 0-9, lo que no se puede
Luigi Plinge

44
Esta expresión regular falla en alrededor de 6000 códigos postales válidos, por lo que recomendaría no hacerlo. Mira mi respuesta .
RichardTowers

esto falla en cualquier código postal en minúsculas o sin espacio para mí
Dancer

14

De acuerdo con esta tabla de Wikipedia

ingrese la descripción de la imagen aquí

Este patrón cubre todos los 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})

Cuando lo use en Android \ Java use \\ d


Encontré esta es la respuesta más legible, aunque solo busca la forma de un código postal, en lugar de códigos válidos reales según las soluciones que toman la información del sitio web gov.uk, pero eso es lo suficientemente bueno para mi caso de uso. Después de jugar un poco (en Python), lo factoricé en una expresión regular un poco más compacta pero equivalente que también permite un espacio 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

La mayoría de las respuestas aquí no funcionaron para todos los códigos postales que tengo en mi base de datos. Finalmente encontré uno que valida con todos, utilizando la nueva expresión regular proporcionada por el gobierno:

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

No está en ninguna de las respuestas anteriores, así que lo publico aquí en caso de que retiren el enlace:

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

ACTUALIZACIÓN: expresiones regulares actualizadas según lo indicado por Jamie Bull. No estoy seguro si fue mi error al copiar o si fue un error en la expresión regular del gobierno, el enlace está caído ahora ...

ACTUALIZACIÓN: Como se encontró en ctwheels, esta expresión regular funciona con el sabor de expresión regular de JavaScript. Vea su comentario para uno que funcione con el sabor pcre (php).


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})$debería 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 la diferencia ;-)
Jamie Bull

1
¡Correcto! Actualicé mi respuesta. ¡Gracias!
Jesús Carrera

2
Esta es la única respuesta aquí que ha funcionado en regexr.com y Notepad ++. Sin embargo, tuve que cambiarlo a ([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})(eliminado ^y $agregado ?después del espacio) para que regexr.com encuentre más de un resultado y para que ambos encuentren un resultado que no tenga un separador de espacio.
mythofechelon

@ctwheels esta expresión regular es para el sabor de JavaScript. Si su enlace falla selecciona javascript, funcionará. Esa es una gran captura y actualizaré mi respuesta.
Jesús Carrera

1
La expresión regular publicada en la documentación es inherentemente incorrecta. La expresión completa debe estar envuelta en un grupo que no sea de captura (?:)y luego anclados colocados a su alrededor. Véalo fallar aquí . Para obtener más información, vea mi respuesta aquí . ^(?:([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}))$es la expresión regular corregida
ctwheels

12

Una publicación antigua pero aún bastante alta en los resultados de Google, así que pensé en actualizar. Este documento del 14 de octubre define la expresión regular del código postal del 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

El documento también explica la lógica detrás de esto. Sin embargo, tiene un error (en negrita) y también permite minúsculas, que aunque no es legal, la versión modificada:

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

Esto funciona con los nuevos códigos postales de Londres (por ejemplo, W1D 5LH) que las versiones anteriores no.


Parece que el error que resaltó en negrita se ha corregido en el documento, pero aún prefiero su expresión regular, ya que es más fácil de leer.
Profesor de programación

55
¿Lo único que diría es hacer que el espacio sea opcional cambiando el espacio a \ s? ya que el espacio no es un requisito para la legibilidad.
Profesor de programación

La expresión regular publicada en la documentación es inherentemente incorrecta. La expresión completa debe estar envuelta en un grupo que no sea de captura (?:)y luego anclados colocados a su alrededor. Véalo fallar aquí . Para obtener más información, vea mi respuesta aquí . ^(?:([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}))$es la expresión regular corregida
ctwheels

10

Esta es la expresión regular que Google sirve en su dominio 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}

10

Los códigos postales están sujetos a cambios, y la única forma verdadera de validar un código postal es tener la lista completa de códigos postales y ver si está allí.

Pero las expresiones regulares son útiles porque:

  • son fáciles de usar e implementar
  • son cortos
  • son rápidos para correr
  • son bastante fáciles de mantener (en comparación con una lista completa de códigos postales)
  • todavía captura la mayoría de los errores de entrada

Pero las expresiones regulares tienden a ser difíciles de mantener, especialmente para alguien a quien no se le ocurrió en primer lugar. Entonces debe ser:

  • tan fácil de entender como sea posible
  • prueba relativamente futura

Eso significa que la mayoría de las expresiones regulares en esta respuesta no son lo suficientemente buenas. Por ejemplo, puedo ver eso[A-PR-UWYZ][A-HK-Y][0-9][ABEHMNPRV-Y] va a coincidir con un área de código postal de la forma AA1A, pero será un dolor de cabeza si se agrega una nueva área de código postal, porque es difícil entender qué áreas de código postal coincide.

También quiero que mi expresión regular coincida con la primera y segunda mitad del código postal como coincidencias entre paréntesis.

Así que se me ocurrió esto:

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

En formato PCRE se puede escribir de la siguiente manera:

/^
  ( 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 mí, este es el equilibrio correcto entre validar tanto como sea posible, mientras que al mismo tiempo ofrece protección contra el futuro y permite un fácil mantenimiento.


No estoy seguro de por qué lo rechazaron: esto funciona con todos los códigos postales válidos que le he arrojado y los espacios que muchas de las respuestas anteriores no manejan correctamente. ¿A alguien le importaría explicar por qué?
Jon

1
@ Jon También coincide cuando se agregan otros caracteres al inicio o al final, por ejemplo, aSW1A 1AAasfgcoinciden para mí (aunque no voté en contra, ya que parece que podría arreglarse fácilmente)
rechaza el

9

He estado buscando una expresión regular del código postal del Reino Unido durante el último día más o menos y me topé con este hilo. Me abrí paso a través de la mayoría de las sugerencias anteriores y ninguna de ellas funcionó para mí, así que se me ocurrió mi propia expresión regular que, hasta donde yo sé, captura todos los códigos postales válidos del Reino Unido a partir de enero '13 (según la última literatura de el correo real).

La expresión regular y algunos códigos postales simples que verifican el código PHP se publican a continuación. NOTA: - Permite códigos postales inferiores o mayúsculos y la anomalía GIR 0AA, pero para tratar con la presencia, más que probable, de un espacio en el medio de un código postal ingresado, también utiliza un simple str_replace para eliminar el espacio antes de la prueba contra la expresión regular. Cualquier discrepancia más allá de eso y el propio Royal Mail ni siquiera las mencionan en su literatura (consulte http://www.royalmail.com/sites/default/files/docs/pdf/programmers_guide_edition_7_v5.pdf y comience a leer desde la página 17) !

Nota: En la propia literatura de Royal Mail (enlace de arriba) hay una ligera ambigüedad en torno a las posiciones tercera y cuarta y las excepciones vigentes si estos caracteres son letras. Me puse en contacto con Royal Mail directamente para aclararlo y en sus propias palabras "Una carta en la cuarta posición del Código Exterior con el formato AANA NAA no tiene excepciones y las excepciones de la tercera posición se aplican solo a la última letra del Código Exterior con el formato ANA NAA ". ¡Directo de la boca del caballo!

<?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 ayude a cualquier persona que se encuentre con este hilo en busca de una solución.


1
Me gustaría saber qué códigos postales de ejemplo le fallaron al publicado.
Zhaph - Ben Duguid

No puedo darle un código postal específico (sin tener acceso a la lista completa de PAF), pero los códigos postales con el formato ANA NAA podrían fallar, ya que las letras P y Q están permitidas en la tercera posición y los códigos postales con el formato AANA NAA potencialmente también falla ya que la cuarta posición permite todas las letras (la expresión regular dada en la respuesta aceptada arriba no tiene en cuenta ninguna de estas). Como digo, solo sigo los consejos actuales de Royal Mail: en el momento de la respuesta anterior, tal vez esa expresión regular cumplió por completo.
Dan Solo

Gracias por el aviso: puedo ver que "P" parece haberse agregado como aceptable en la tercera posición (de su documento vinculado), pero no Q, pero ¿dónde está leyendo que "la cuarta posición permite todas las letras"? El documento no menciona la "cuarta posición" en lo que puedo ver, así que lo leería como "la tercera letra, independientemente de la posición real".
Zhaph - Ben Duguid

1
Acabo de recibir noticias del equipo de soporte de Royal Mail y aparentemente mi interpretación de las reglas es correcta. Una letra en la cuarta posición del Código Exterior (por ejemplo, AANA NAA) no tiene excepciones y las excepciones de la tercera posición se aplican solo a la última letra (por ejemplo, ANA NAA). Directo de la boca del caballo.
Dan Solo

1
@DanSolo Esta expresión regular devolverá una coincidencia verdadera para la primera mitad de un código postal válido que no SW1ABD25
tenga

7

Aquí hay una expresión regular basada en el formato especificado en los documentos que están vinculados a la respuesta de marcj:

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

La única diferencia entre eso y las especificaciones es que los últimos 2 caracteres no pueden estar en [CIKMOV] de acuerdo con las especificaciones.

Editar: Aquí hay otra versión que prueba las limitaciones de los caracteres finales.

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

Hay muchas más complejidades para un código postal del Reino Unido que simplemente aceptar A-Z: Qnunca se permite, Vsolo se usa con moderación, etc., dependiendo de la posición del personaje.
Zhaph - Ben Duguid

2
Eso puede ser irrelevante si lo que quieres es una verificación de sintaxis. Como muchos otros han comentado, solo una búsqueda en una base de datos actualizada se vuelve casi correcta, e incluso entonces existe el problema de cuán actualizada está la base de datos. Entonces, para mí, esta regex del verificador de sintaxis es clara, simple y útil.
Rick-777

5

Algunas de las expresiones regulares anteriores son un poco restrictivas. Tenga en cuenta el código postal original: "W1K 7AA" fallaría dada la regla "Posición 3 - AEHMNPRTVXY solo se usa" arriba, ya que "K" no se permitirá.

la expresión regular:

^(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 un poco más preciso, vea el artículo de Wikipedia titulado 'Códigos postales en el Reino Unido' .

Tenga en cuenta que esta expresión regular requiere solo caracteres en mayúscula.

La pregunta más importante es si está restringiendo la entrada del usuario para permitir solo códigos postales que realmente existen o si simplemente está tratando de evitar que los usuarios ingresen basura completa en los campos del formulario. Hacer coincidir correctamente todos los códigos postales posibles, y probarlo en el futuro, es un rompecabezas más difícil, y probablemente no valga la pena a menos que sea HMRC.


Parece que la oficina de correos ha avanzado, pero el gobierno se está quedando un poco atrás :(
Zhaph - Ben Duguid

44
Yo 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}) $ "Me gusta porque permite mayúsculas y minúsculas y hace que el espacio sea opcional, ¡mejor para la usabilidad, si no 100% correcto!
bigtv

4

Así es como hemos estado lidiando con el problema del código postal del Reino Unido:

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

Explicación:

  • esperar 1 o 2 caracteres az, superior o inferior fina
  • esperar 1 o 2 números
  • esperar 0 o 1 az char, superior o inferior fina
  • espacio opcional permitido
  • esperar 1 número
  • esperar 2 az, multa superior o inferior

Esto obtiene la mayoría de los formatos, luego usamos el db para validar si el código postal es realmente real, estos datos son controlados por punto abierto https://www.ordnancesurvey.co.uk/opendatadownload/products.html

espero que esto ayude


Esto permite el formato AANNA NAA, que no es válido.
ctwheels

De ahí la parte de la respuesta 'Esto obtiene la mayoría de los formatos'. :)
Alex Stephens

4

Reglas básicas:

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

Los códigos postales en el Reino Unido (o códigos postales, como se los llama) están compuestos de cinco a siete caracteres alfanuméricos separados por un espacio. Las reglas que cubren qué personajes pueden aparecer en posiciones particulares son bastante complicadas y están llenas de excepciones. La expresión regular que se acaba de mostrar se ajusta a las reglas básicas.

Reglas completas:

Si necesita una expresión regular que cumple todos los requisitos para las reglas del código postal a expensas de la legibilidad, aquí tiene:

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

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

Probado contra la base de datos de nuestros clientes y parece perfectamente preciso.


4

Utilizo la siguiente expresión regular que he probado con todos los códigos postales válidos del Reino Unido. Se basa en las reglas recomendadas, pero se condensa tanto como sea razonable y no utiliza ninguna regla de expresión regular específica de un idioma especial.

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

Se supone que el código postal se ha convertido a mayúsculas y no tiene caracteres iniciales o finales, pero aceptará un espacio opcional entre el código externo y el código interno.

El código postal especial "GIR0 0AA" está excluido y no se validará, ya que no está en la lista oficial de códigos postales de la Oficina de Correos y, que yo sepa, no se utilizará como dirección registrada. Agregarlo debería ser trivial como un caso especial si es necesario.


4

Quería una expresión regular simple, donde está bien permitir demasiado, pero no negar un código postal válido. Fui con esto (la entrada es una cadena despojada / recortada):

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

Esto permite los códigos postales más cortos posibles como "L1 8JQ", así como los más largos como "OL14 5ET".

Debido a que permite hasta 8 caracteres, también permitirá códigos postales incorrectos de 8 caracteres si no hay espacio: "OL145ETX". Pero, de nuevo, esta es una expresión regular simplista, para cuando eso es lo suficientemente bueno.


Oh, mis disculpas. Creo que me perdí el / i cuando estaba probando ayer.
John

3

Primera mitad del 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]

Excepciones
Posición 1 - QVX no utilizado
Posición 2 - IJZ no utilizado excepto en GIR 0AA
Posición 3 - AEHMNPRTVXY solo utilizado
Posición 4 - ABEHMNPRVWXY

Segunda mitad del código postal

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

Excepciones
Posición 2 + 3 - CIKMOV no utilizado

Recuerde que no se utilizan todos los códigos posibles, por lo que esta lista es una condición necesaria pero no suficiente para un código válido. ¿Sería más fácil hacer coincidir una lista de todos los códigos válidos?


3

Para verificar que un código postal esté en un formato válido según la guía del programador de 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 los códigos postales en doogal.co.uk coinciden, excepto los que ya no están en uso.

Agregar un ?espacio después del espacio y usar una coincidencia entre mayúsculas y minúsculas para responder esta pregunta

'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" ]

3

Éste permite espacios vacíos y pestañas de ambos lados en caso de que no desee fallar la validación y luego recortarlo del lado del servidor.

^\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*$)

Este es el único patrón que funcionó para mí usando c # (System.Text.RegularExpressions) con los ejemplos descritos en la pregunta original
MattjeS,

Esta es la expresión regular rota del gobierno del Reino Unido y no puede validar algunos de los formatos válidos.
ctwheels

@ctwheels Hola, ¿podría proporcionar un código postal defectuoso? Gracias.
Matas Vaitkevicius

Por ejemplo, AAA 1AAno es un formato válido: vea mi respuesta para obtener una explicación y solución.
ctwheels

2

Para agregar a esta lista, una expresión regular más práctica que utilizo que permite al usuario ingresar una empty stringes:

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

Esta expresión regular permite letras mayúsculas y minúsculas con un espacio opcional en el medio

Desde el punto de vista de los desarrolladores de software, esta expresión regular es útil para el software donde una dirección puede ser opcional. Por ejemplo, si un usuario no desea proporcionar los detalles de su dirección


1

Echa un vistazo al código de Python en esta página:

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

Tengo que analizar algunos códigos postales. El requisito es bastante simple; Tengo que analizar un código postal en un código de salida y un código de entrada (opcional). La buena noticia es que no tengo que realizar ninguna validación, solo tengo que cortar lo que me han proporcionado de una manera vagamente inteligente. No puedo asumir mucho sobre mi importación en términos de formato, es decir, mayúsculas y minúsculas. Pero esta no es la mala noticia; La mala noticia es que tengo que hacerlo todo en RPG. :-(

Sin embargo, agregué una pequeña función de Python para aclarar mi pensamiento.

Lo he usado para procesar códigos postales para mí.


1

Nos dieron una especificación:

Los códigos postales del Reino Unido deben estar en una de las siguientes formas (con una excepción, ver abajo): 
    § A9 9AA 
    § A99 9AA
    § AA9 9AA
    § AA99 9AA
    § A9A 9AA
    § AA9A 9AA
donde A representa un carácter alfabético y 9 representa un carácter numérico.
Se aplican reglas adicionales a los caracteres alfabéticos, de la siguiente manera:
    § El personaje en la posición 1 puede no ser Q, V o X
    § El personaje en la posición 2 puede no ser I, J o Z
    § El personaje en la posición 3 puede no ser I, L, M, N, O, P, Q, R, V, X, Y o Z
    § El personaje en la posición 4 puede no ser C, D, F, G, I, J, K, L, O, Q, S, T, U o Z
    § Los caracteres en las dos posiciones de la derecha pueden no ser C, I, K, M, O o V
La única excepción que no sigue estas reglas generales es el código postal "GIR 0AA", que es un código postal válido especial.

Se nos ocurrió esto:

/^([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

Pero tenga en cuenta: esto permite cualquier cantidad de espacios entre grupos.


2
paulslater19, desafortunadamente su solución permite los códigos postales A99A 9AA.

1

Tengo la expresión regular para la validación del código postal del Reino Unido.

Esto funciona para todo tipo de código postal, ya sea interno o 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}))$

Esto funciona para todo tipo de formato.

Ejemplo:

AB10 --------------------> SOLO CÓDIGO POSTAL EXTERIOR

A1 1AA ------------------> COMBINACIÓN DE CÓDIGO POSTAL (EXTERIOR E INTERNO)

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


1

La respuesta aceptada refleja las reglas dadas por Royal Mail, aunque hay un error tipográfico en la expresión regular. Este error tipográfico parece haber estado allí también en el sitio gov.uk (como en la página de archivo XML).

En el formato A9A 9AA, las reglas permiten un carácter P en la tercera posición, mientras que la expresión regular no lo permite. La expresión regular correcta sería:

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

Acortar esto da como resultado la siguiente expresión regular (que usa la sintaxis 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})

También incluye un espacio opcional entre el primer y el segundo bloque.


1

Lo que he encontrado en casi todas las variaciones y la expresión regular del pdf de transferencia masiva y lo que está en el sitio de Wikipedia es esto, específicamente para la expresión regular de Wikipedia, debe haber un ^ después de la primera | (barra vertical). Lo descubrí probando AA9A 9AA, porque de lo contrario la verificación de formato para A9A 9AA lo validará. Por ejemplo, la comprobación de EC1D 1BB que debería ser inválido vuelve a ser válido porque C1D 1BB es un formato válido.

Esto es lo que se me ocurrió para una buena expresión regular:

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

1

A través de pruebas y observaciones empíricas, además de confirmar con https://en.wikipedia.org/wiki/Postcodes_in_the_United_Kingdom#Validation , aquí está mi versión de una expresión regular de Python que analiza y valida correctamente un código postal del 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})'

Esta expresión regular es simple y tiene grupos de captura. Que no incluye todas las validaciones de legales códigos postales del Reino Unido, pero sólo tiene en cuenta la letra vs posiciones numéricas.

Así es como lo usaría en el 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

Aquí hay pruebas unitarias:

@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)

0

Necesitaba una versión que funcionara en SAS con las PRXMATCHfunciones relacionadas, así que se me ocurrió esto:

^[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 prueba y 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;

0

El siguiente método verificará el código postal y proporcionará información completa

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!"}
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.