regex - solo - validar fecha javascript expresion regular
Expresión regular para unir fechas válidas (15)
Intento escribir una expresión regular que valida una fecha. La expresión regular debe coincidir con la siguiente
- M / D / YYYY
- MM / DD / YYYY
- Los meses de un solo dígito pueden comenzar con un cero inicial (p. Ej .: 03/12/2008)
- Los días de un solo dígito pueden comenzar con un cero inicial (p. Ej .: 3/02/2008)
- NO PUEDE incluir el 30 de febrero o el 31 de febrero (p. Ej .: el 31/1/2008)
Hasta ahora tengo
^(([1-9]|1[012])[-/.]([1-9]|[12][0-9]|3[01])[-/.](19|20)/d/d)|((1[012]|0[1-9])(3[01]|2/d|1/d|0[1-9])(19|20)/d/d)|((1[012]|0[1-9])[-/.](3[01]|2/d|1/d|0[1-9])[-/.](19|20)/d/d)$
Esto coincide adecuadamente, EXCEPTO, sigue incluyendo 2/30/2008 y 2/31/2008.
¿Alguien tiene una mejor sugerencia?
Editar: Encontré la respuesta en RegExLib
^((((0[13578])|([13578])|(1[02]))[//](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[//](([1-9])|([0-2][0-9])|(30)))|((2|02)[//](([1-9])|([0-2][0-9]))))[//]/d{4}$|^/d{4}$
Coincide con todos los meses válidos que siguen el formato MM / DD / YYYY.
Gracias a todos por la ayuda.
Versión Perl 6
rx{
^
$<month> = (/d ** 1..2)
{ $<month> <= 12 or fail }
''/''
$<day> = (/d ** 1..2)
{
given( +$<month> ){
when 1|3|5|7|8|10|12 {
$<day> <= 31 or fail
}
when 4|6|9|11 {
$<day> <= 30 or fail
}
when 2 {
$<day> <= 29 or fail
}
default { fail }
}
}
''/''
$<year> = (/d ** 4)
$
}
Después de usar esto para verificar la entrada, los valores están disponibles en $/
o individualmente como $<month>
, $<day>
, $<year>
. (esos son solo la sintaxis para acceder a los valores en $/
)
No se ha intentado verificar el año, o no coincide con el 29 de febrero en años no bisiestos.
Versión ampliada Perl
Tenga en cuenta el uso del modificador /x
.
/^(
(
( # 31 day months
(0[13578])
| ([13578])
| (1[02])
)
[//]
(
([1-9])
| ([0-2][0-9])
| (3[01])
)
)
| (
( # 30 day months
(0[469])
| ([469])
| (11)
)
[//]
(
([1-9])
| ([0-2][0-9])
| (30)
)
)
| ( # 29 day month (Feb)
(2|02)
[//]
(
([1-9])
| ([0-2][0-9])
)
)
)
[//]
# year
/d{4}$
| ^/d{4}$ # year only
/x
Original
^((((0[13578])|([13578])|(1[02]))[//](([1-9])|([0-2][0-9])|(3[01])))|(((0[469])|([469])|(11))[//](([1-9])|([0-2][0-9])|(30)))|((2|02)[//](([1-9])|([0-2][0-9]))))[//]/d{4}$|^/d{4}$
Versión perceptible de Perl 5.10
/
(?:
(?<month> (?&mon_29)) [//] (?<day>(?&day_29))
| (?<month> (?&mon_30)) [//] (?<day>(?&day_30))
| (?<month> (?&mon_31)) [//] (?<day>(?&day_31))
)
[//]
(?<year> [0-9]{4})
(?(DEFINE)
(?<mon_29> 0?2 )
(?<mon_30> 0?[469] | (11) )
(?<mon_31> 0?[13578] | 1[02] )
(?<day_29> 0?[1-9] | [1-2]?[0-9] )
(?<day_30> 0?[1-9] | [1-2]?[0-9] | 30 )
(?<day_31> 0?[1-9] | [1-2]?[0-9] | 3[01] )
)
/x
Puede recuperar los elementos por nombre en esta versión.
say "Month=$+{month} Day=$+{day} Year=$+{year}";
(No se ha intentado restringir los valores del año).
Aquí está el Reg ex que coincide con todas las fechas válidas, incluidos los años bisiestos. Formatos aceptados mm / dd / aaaa o mm-dd-aaaa o formato mm.dd.aaaa
^(?:(?:(?:0?[13578]|1[02])(//|-|/.)31)/1|(?:(?:0?[1,3-9]|1[0-2])(//|-|/.)(?:29|30)/2))(?:(?:1[6-9]|[2-9]/d)?/d{2})$|^(?:0?2(//|-|/.)29/3(?:(?:(?:1[6-9]|[2-9]/d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:(?:0?[1-9])|(?:1[0-2]))(//|-|/.)(?:0?[1-9]|1/d|2[0-8])/4(?:(?:1[6-9]|[2-9]/d)?/d{2})$
cortesía Asiq Ahamed
Aterricé aquí porque el título de esta pregunta es amplio y estaba buscando una expresión regular que pudiera usar para unirme a un formato de fecha específico (como el OP). Pero luego descubrí que, como muchas de las respuestas y comentarios han destacado exhaustivamente, existen muchas trampas que hacen que construir un patrón efectivo sea muy complicado cuando se extraen fechas que están mezcladas con datos de fuente no estructurada o de baja calidad.
En mi exploración de los problemas, he creado un sistema que le permite construir una expresión regular organizando juntas cuatro sub-expresiones más simples que coinciden en el delimitador, y rangos válidos para los campos de año, mes y día en el orden Necesitas.
Estos son :-
Delímetros
[^/w/d/r/n:]
Esto coincidirá con cualquier cosa que no sea un carácter de palabra, un dígito, un retorno de carro, una nueva línea o dos puntos. El colon debe estar allí para evitar coincidencias en horarios que parecen fechas (ver mis datos de prueba)
Puede optimizar esta parte del patrón para acelerar la coincidencia, pero esta es una buena base que detecta la mayoría de los delimitadores válidos.
Tenga en cuenta sin embargo; Coincidirá con una cadena con delimitadores mixtos como este 2 / 12-73 que puede no ser una fecha válida.
Valores del año
(/d{4}|/d{2})
Esto coincide con un grupo de dos o 4 dígitos, en la mayoría de los casos esto es aceptable, pero si se trata de datos de los años 0-999 o más allá de 9999, debe decidir cómo manejar eso porque en la mayoría de los casos, 1, 3 o> año de 4 dígitos es basura.
Valores del mes
(0?[1-9]|1[0-2])
Coincide con cualquier número entre 1 y 12 con o sin una nota cero inicial: 0 y 00 no coinciden.
Valores de fecha
(0?[1-9]|[12]/d|30|31)
Coincide con cualquier número entre 1 y 31 con o sin una nota cero inicial: 0 y 00 no coinciden.
Esta expresión coincide con fechas formateadas de fecha, mes y año
(0?[1-9]|[12]/d|30|31)[^/w/d/r/n:](0?[1-9]|1[0-2])[^/w/d/r/n:](/d{4}|/d{2})
Pero también coincidirá con algunas de las fechas de Año, Mes. También se debe reservar con los operadores de límites para garantizar que se selecciona la cadena de fecha completa y evitar que se extraigan subdatos válidos a partir de datos que no están bien formados, es decir, sin etiquetas de límite 20/12/194 coincide con 20/12/19 y 101/12/1974 coincide con el 01/12/1974
Compare los resultados de la siguiente expresión con los de arriba con los datos de prueba en la sección sin sentido (abajo)
/b(0?[1-9]|[12]/d|30|31)[^/w/d/r/n:](0?[1-9]|1[0-2])[^/w/d/r/n:](/d{4}|/d{2})/b
No hay validación en esta expresión regular por lo que una fecha bien formada pero no válida como 31/02/2001 se correspondería. Ese es un problema de calidad de datos, y como otros han dicho, su expresión regular no debería necesitar validar los datos.
Debido a que usted (como desarrollador) no puede garantizar la calidad de los datos de origen que necesita realizar y manejar la validación adicional en su código, si intenta hacer coincidir y validar los datos en el RegEx se vuelve muy complicado y se vuelve difícil soporte sin una documentación muy concisa.
Basura dentro basura fuera.
Habiendo dicho eso, si tiene formatos mixtos donde los valores de fecha varían, y tiene que extraer todo lo que pueda; Puede combinar un par de expresiones juntas de esa manera;
Esta expresión (desastrosa) coincide con las fechas DMY y YMD
(/b(0?[1-9]|[12]/d|30|31)[^/w/d/r/n:](0?[1-9]|1[0-2])[^/w/d/r/n:](/d{4}|/d{2})/b)|(/b(0?[1-9]|1[0-2])[^/w/d/r/n:](0?[1-9]|[12]/d|30|31)[^/w/d/r/n:](/d{4}|/d{2})/b)
PERO no podrá decir si las fechas como el 6/9/1973 son el 6 de septiembre o el 9 de junio. Estoy luchando por pensar en un escenario donde eso no vaya a causar problemas en algún momento, es una mala práctica y no deberías lidiar con eso de esa manera: encuentra al propietario de los datos y golpéalos con el martillo de gobernanza .
Finalmente, si quiere hacer coincidir una cadena YYYYMMDD sin delimitadores, puede sacar algo de incertidumbre y la expresión se ve así:
/b(/d{4})(0[1-9]|1[0-2])(0[1-9]|[12]/d|30|31)/b
Pero tenga en cuenta que coincidirá en valores bien formados pero no válidos como 20010231 (31 de febrero) :)
Datos de prueba
Al experimentar con las soluciones en este hilo, terminé con un conjunto de datos de prueba que incluye una variedad de fechas válidas y no válidas y algunas situaciones complicadas en las que puede o no desear coincidir, es decir, tiempos que pueden coincidir con fechas y fechas múltiples líneas
Espero que esto sea útil para alguien.
Valid Dates in various formats
Day, month, year
2/11/73
02/11/1973
2/1/73
02/01/73
31/1/1973
02/1/1973
31.1.2011
31-1-2001
29/2/1973
29/02/1976
03/06/2010
12/6/90
month, day, year
02/24/1975
06/19/66
03.31.1991
2.29.2003
02-29-55
03-13-55
03-13-1955
12/24/1974
12/30/1974
1/31/1974
03/31/2001
01/21/2001
12/13/2001
Match both DMY and MDY
12/12/1978
6/6/78
06/6/1978
6/06/1978
using whitespace as a delimiter
13 11 2001
11 13 2001
11 13 01
13 11 01
1 1 01
1 1 2001
Year Month Day order
76/02/02
1976/02/29
1976/2/13
76/09/31
YYYYMMDD sortable format
19741213
19750101
Valid dates before Epoch
12/1/10
12/01/660
12/01/00
12/01/0000
Valid date after 2038
01/01/2039
01/01/39
Valid date beyond the year 9999
01/01/10000
Dates with leading or trailing characters
12/31/21/
31/12/1921AD
31/12/1921.10:55
12/10/2016 8:26:00.39
wfuwdf12/11/74iuhwf
fwefew13/11/1974
01/12/1974vdwdfwe
01/01/99werwer
12321301/01/99
Times that look like dates
12:13:56
13:12:01
1:12:01PM
1:12:01 AM
Dates that runs across two lines
1/12/19
74
01/12/19
74/13/1946
31/12/20
08:13
Invalid, corrupted or nonsense dates
0/1/2001
1/0/2001
00/01/2100
01/0/2001
0101/2001
01/131/2001
31/31/2001
101/12/1974
56/56/56
00/00/0000
0/0/1999
12/01/0
12/10/-100
74/2/29
12/32/45
20/12/194
2/12-73
Esta expresión regular valida las fechas entre el 01-01-2000 y el 12-31-2099 con separadores coincidentes.
^(0[1-9]|1[012])([- /.])(0[1-9]|[12][0-9]|3[01])/2(19|20)/d/d$
Este no es un uso apropiado de expresiones regulares. Estarías mejor usando
[0-9]{2}/[0-9]{2}/[0-9]{4}
y luego verificar rangos en un lenguaje de nivel superior.
Para controlar una validez de fecha en el siguiente formato:
AAAA / MM / DD o AAAA-MM-DD
Te recomiendo que uses la siguiente expresión regular:
(((19|20)([2468][048]|[13579][26]|0[48])|2000)[/-]02[/-]29|((19|20)[0-9]{2}[/-](0[4678]|1[02])[/-](0[1-9]|[12][0-9]|30)|(19|20)[0-9]{2}[/-](0[1359]|11)[/-](0[1-9]|[12][0-9]|3[01])|(19|20)[0-9]{2}[/-]02[/-](0[1-9]|1[0-9]|2[0-8])))
Partidos
2016-02-29 | 2012-04-30 | 2019/09/31
No coincidencias
2016-02-30 | 2012-04-31 | 2019/09/35
Puede personalizarlo si quiere permitir solo separadores ''/'' o ''-''. Este RegEx controla estrictamente la validez de la fecha y verifica 28,30 y 31 días meses, incluso años bisiestos con 29/02 mes.
Pruébalo, funciona muy bien y evita tu código de muchos errores.
FYI: hice una variante para el horario de SQL. Lo encontrarás allí (busca mi nombre): Expresión regular para validar una marca de tiempo
Los comentarios son bienvenidos :)
Parece que estás exagerando la expresión regular para este propósito. Lo que haría sería usar una expresión regular para que coincida con algunos formatos de fecha y luego usar una función separada para validar los valores de los campos de fecha así extraídos.
Regex no estaba destinado a validar los rangos numéricos (este número debe ser de 1 a 5 cuando el número que le precede es 2 y el número anterior que está por debajo de 6). Solo busca el patrón de ubicación de los números en expresiones regulares. Si necesita validar las cualidades de una fecha, póngala en un objeto de fecha js / c # / vb, e intercalcule los números allí.
Sé que esto no responde a su pregunta, pero ¿por qué no utiliza una rutina de manejo de fechas para verificar si es una fecha válida? Incluso si modifica la expresión regular con una aserción negativa de búsqueda anticipada como (?! 31/0? 2) (es decir, no coincide con 31/2 o 31/02), seguirá teniendo el problema de aceptar 29 02 en años no bisiestos. y sobre un solo formato de fecha de separador.
El problema no es fácil si realmente quieres validar una fecha, mira este hilo del foro .
Para un ejemplo o una forma mejor, en C #, consulte este enlace
Si está utilizando otra plataforma / idioma, infórmenos
Si no conseguiste que funcionaran las sugerencias anteriores, utilizo esto, ya que en cualquier fecha ejecuto esta expresión a través de 50 enlaces, y obtuve todas las fechas en cada página.
^20/d/d-(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)-(0[1-9]|[1-2][0-9]|3[01])$
Si vas a insistir en hacer esto con una expresión regular, te recomendaría algo como:
( (0?1|0?3| <...> |10|11|12) / (0?1| <...> |30|31) |
0?2 / (0?1| <...> |28|29) )
/ (19|20)[0-9]{2}
Esto podría permitir leer y comprender.
Un enfoque ligeramente diferente que puede o no serle útil.
Estoy en php.
El proyecto al que se refiere esto nunca tendrá una fecha anterior al 1 de enero de 2008. Por lo tanto, tomo la ''fecha'' inputed y uso strtotime (). Si la respuesta es> = 1199167200, entonces tengo una fecha que me es útil. Si se ingresa algo que no se parece a una fecha, se devuelve -1. Si se ingresa nulo, devuelve el número de fecha de hoy, por lo que primero necesita una verificación para una entrada que no sea nula.
¿Funciona para mi situación, tal vez la tuya también?
var dtRegex = new RegExp(/[1-9/-]{4}[0-9/-]{2}[0-9/-]{2}/);
if(dtRegex.test(date) == true){
var evalDate = date.split(''-'');
if(evalDate[0] != ''0000'' && evalDate[1] != ''00'' && evalDate[2] != ''00''){
return true;
}
}