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 1AA
pasa. 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 0AAfoo
lo 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 A
representa una letra y N
representa un número), y comienza con cualquier cosa que no sea A
oZ
, fallará.
Eso significa que coincidirá A1A 1AA
y Z1A 1AA
, pero no B1A 1AA
.
Para solucionar este problema, el carácter se -
debe colocar entre A
y Z
en 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 0AA
al 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 TA1
es un código postal válido. Una expresión regular para esto es muy simple:
^SAN ?TA1$