Quiero validar un campo de entrada con expresión regular en JavaScript, que debería validar los siguientes casos:
Válido:
A and B and C and D (A or B) and C (A or B or C) and D (A or B or C or D) and E A and (B or C) and D A and (B or C) or (C and D) A or (B and C) (A and B) or (C and D)Inválido:
A and B and C and (A or B and C (A or B or C) and D or (A or B or C or D and E A and or (B or C) and D A and (B or (C and D))) A (B and C) (A and B) or C and D) (A and B or C and D)Básicamente, necesito una letra de la A a la Z (solo en mayúsculas) seguida de "y" o "o" y paréntesis ilimitados, pero la cantidad de paréntesis de apertura debe coincidir con la cantidad de paréntesis de cierre. Además, después de un corchete de apertura, debería poder insertar solo AZ en mayúsculas y después de un corchete de cierre, "y", "o" o AZ en mayúsculas también deberían ser válidos. Los corchetes anidados tampoco deberían ser válidos.
Se me ocurrió esta solución, pero solo está validando AZ en mayúsculas, "y" y "o" palabras y corchetes, por lo que todos los casos no válidos proporcionados coinciden con mi expresión regular.
/^[AZ(]?[AZ]| |and|or|[(]|[AZ]|[)]/gmSin corchetes anidados, esto es fácil. Una cláusula disyuntiva de la forma normal conjuntiva es
[AZ]( or [AZ])* Con paréntesis requeridos alrededor de cláusulas usando or :
[AZ]|\([AZ]( or [AZ])*\)La fórmula completa sería entonces
([AZ]|\([AZ]( or [AZ])*\))( and ([AZ]|\([AZ]( or [AZ])*\)))*Una expresión regular JS podría ser:
^(?!\([^()]*\)$|.*([()])[^()]*(?=\1)|[^()]*[()](?:[^()]*[()][^()]*[()])*[^()]*$|.*\([AZ]\))\(?[AZ](?: (?:and|or) \(?[AZ]\)?)*$Ver una demostración en línea
^ - Anclaje de línea de salida;(?! - Abre una búsqueda anticipada negativa con alternancias;\([^()]*\)$ : evita una coincidencia con un paréntesis de apertura, 0+ caracteres que no sean paréntesis y un paréntesis de cierre. O;.*([()])[^()]*(?=\1) - 0+ Carácter hasta un paréntesis de apertura/cierre en un primer grupo de captura seguido de 0+ caracteres que no sean paréntesis hasta una referencia inversa al primer grupo. O;[^()]*[()](?:[^()]*[()][^()]*[()])*[^()]*$ - Una comprobación de paréntesis desequilibrada. El patrón exigirá que haya un múltiplo de dos paréntesis si se ha utilizado alguno. O;.*\([AZ]\) - Prueba para 0+ caracteres seguidos de apertura, letra mayúscula y cierre directo, para evitar una entrada tipo (A) ;\(?[AZ] - Coincide con un paréntesis opcional seguido de AZ (para permitir que una sola letra también sea una coincidencia válida);(?: (?:and|or) \(?[AZ]\)?)* - Abre un grupo sin captura para que coincida con un espacio, un grupo sin captura anidado para que coincida y|o seguido de otro espacio, un paréntesis de apertura opcional, otra letra mayúscula y un paréntesis de cierre opcional. Esta agrupación coincide más de 0 veces;$ - Anclaje de línea final.Uno realmente interesante... Jugando un poco con los límites de las palabras , el más corto que se me ocurrió hasta ahora:
^(?:(?: (?:or|and) )?(?:\b[AZ]|\B\([AZ](?: (?:or|and) [AZ])+\)\B)){2,}$Aquí hay una demostración en regex101
Avíseme dónde/si falla, tengo la sensación de que todavía no funciona correctamente.