Estoy tratando de validar una cadena de la forma en que se hace en Jira en Javascript. Estoy tratando de replicar cómo se valida en Jira. Supongo que podría hacer esto con Regex, pero no estoy seguro de cómo.
Un usuario puede escribir una cadena con el formato "1d 6h 30m", lo que significaría 1 día, 6 horas, 30 minutos. No necesito las semanas para mi caso de uso. Quiero mostrar un error si el usuario usa un carácter no válido (cualquier cosa excepto 'd', 'h', 'm' o ' '). Además, la cadena debe separar las duraciones de tiempo por espacios e, idealmente, me gustaría obligar al usuario a ingresar las duraciones de tiempo en orden descendente, lo que significa que '6h 1d' no sería válido porque los días deberían ser los primeros. Además, el usuario no tiene que ingresar toda la información, por lo que '30m' sería válido.
Este es mi código para obtener los días, horas y minutos que parece funcionar. Solo necesito ayuda con la parte de validación.
let time = '12h 21d 30m'; //example let times = time.split(' '); let days = 0; let hours = 0; let min = 0; for(let i = 0; i < times.length; i++) { if (times[i].includes('d')){ days = times[i].split('d')[0]; } if (times[i].includes('h')){ hours = times[i].split('h')[0]; } if (times[i].includes('m')){ min = times[i].split('m')[0]; } } console.log(days); console.log(hours); console.log(min);
Según su comentario, he agregado una expresión regular de validación para que se ejecute primero antes de ejecutar la expresión regular de coincidencia.
Para la validación, desea
/^(\d+[d]\s+)?(\d+[h]\s+)?(\d+[m]\s+)?(\d+[s]\s+|$)?/
Para extraer valores, desea
/([\d]+[dhms]\s+|$)/g
Luego puede usar String.match con esta expresión regular, iterando a través de todas las coincidencias y agregando tiempo según la letra de tiempo al final
const INPUT = "12h 21d 30s"; checkTimespanFormat(INPUT); if (checkTimespanKeysOrder(INPUT, true)) console.log(`${INPUT} keys order is valid`); else console.log(`${INPUT} keys order is NOT valid`); //****************************************************************** /** * Ensures that time keys are: * - Preceeded by one or two digits * - Separated by one or many spaces */ function checkTimespanFormat(timespanStr, maltiSpacesSeparation = false) { // timespan items must be separated by 1 space if (maltiSpacesSeparation) timespanStr = timespanStr.toLowerCase().split(" "); // timespan items must be separated by one or many space else timespanStr = timespanStr.toLowerCase().split(/ +/); // timespan items must be formatted correctly timespanStr.forEach((item) => { if (!/^\d{1,2}[dhms]$/.test(item)) console.log("invalid", item); else console.log("valid", item); }); } /** * Validates: * - Keys order * - Duplicate keys */ function checkTimespanKeysOrder(timespanStr) { const ORDER = ["d", "h", "m", "s"]; let timeKeysOrder = timespanStr .replace(/[^dhms]/g, "") // Removing non time keys characters .split("") // toArray .map((char) => { return ORDER.indexOf(char); // Getting the order of time keys }); for (i = 0; i < timeKeysOrder.length - 1; i++) if (timeKeysOrder.at(i) >= timeKeysOrder.at(i + 1)) return false; return true; }
Aquí está mi opinión sobre el problema:
([1-5]?[\d])m
, con valores elegibles en el rango [0,59]([1]?[\d]|2[0-3])h
, con valores elegibles en el rango [0,23]([1-9]|[1-9][\d])d
, con valores elegibles en el rango [1,99] Luego, podemos encapsular expresiones regulares para días en horas y expresiones regulares para horas en minutos para asegurarnos de que tenemos formatos como {dd}d {hh}h {mm}m
, {hh}h {mm}m
, {mm}m
:
"(((([1-9]|[1-9][\d])d )?([1]?[\d]|2[0-3])h )*([1-5]?[\d])m)"
Los casos de esquina incluyen entradas con ceros como 00m
, 00d 00m
, 01h 00d 00m
. Para rechazar los dos primeros y aceptar el último, podemos negar los valores 00m
y 00d
cuando no se encuentran los patrones anteriores.
Regex final a usar:
"(?!0m)(((?!0h)(([1-9]|[1-9][\d])d )?([1]?[\d]|2[0-3])h )*([1-5]?[\d])m)"
Comprobar:
days
en el Grupo 4hours
en el Grupo 5minutes
en el Grupo 6Probado en https://regex101.com .
¿Resuelve tu problema?