2009-09-29 19 views
5

Lo que necesito es verificar si una cadena dada coincide parcialmente con una expresión regular determinada. Por ejemplo, para la expresión regular ab[0-9]c, las cadenas "a", "ab", "ab3" y "b3c" coincidirían, pero no las cadenas "d", "abc" o "a3c". Lo que he estado haciendo es el torpe a(?:b(?:[0-9](?:c)?)?)? (que solo funciona para algunas de las coincidencias parciales, específicamente aquellas que "comienzan" a coincidir), pero dado que esto es parte de una API, prefiero darles a los usuarios una intuición más intuitiva. forma de ingresar sus expresiones regulares coincidentes.¿Existe una forma elegante de hacer coincidencias parciales de expresiones regulares en Java?

En caso de que la descripción no sea muy clara (y me doy cuenta de que podría no ser así), se usará para validar el ingreso de texto en cuadros de texto. Quiero evitar cualquier edición que daría como resultado una cadena no válida, pero no puedo hacer coincidir la cadena con una expresión regular, ya que hasta que no se ingrese por completo, no coincidirá. Por ejemplo, usando la expresión regular anterior (ab[0-9]c), cuando intento ingresar 'a', no se permite, ya que la cadena "a" no coincide con la expresión regular.

Básicamente, es una especie de startsWith() inversa que funciona en expresiones regulares. (new Pattern("ab[0-9]c").startsWith("ab3") debe devolver true.)

¿Alguna idea?

+0

FYI: 'un (?: B (?:?? [0-9] (?: c)))?' Coincidirá * cualquier cadena * que contiene un "a", tal como "jazz ". Desea utilizar '^ a (?: B (?: [0-9] (?: c)?)?)? $' Para que coincida con toda la cadena. – Kip

+0

¿Son todas las expresiones regulares que el cliente usa tan simples como 'ab [0-9] c', o necesitará una coincidencia más compleja (es decir, con subgrupos)? – Kip

+0

Oops ... sí, los^y $ se agregan automáticamente a la expresión regular, por lo que no los agregué, gracias. Y no, las expresiones regulares no son tan simples, pueden volverse bastante complejas, aunque no tan lejos como para requerir subgrupos. – Tonio

Respuesta

6

¿Es Matcher.hitEnd() lo que estás buscando?

Pattern thePattern = Pattern.compile(theRegexString); 
Matcher m = thePattern.matcher(theStringToTest); 
if (m.matches()) { 
    return true; 
} 
return m.hitEnd(); 
+0

¡Agradable! Casi funciona. Ciertamente funciona como un reemplazo de lo que estoy haciendo actualmente. Todavía no funcionará para coincidencias de cola parciales (por ejemplo, "b3c" es una coincidencia parcial de cola para 'ab [0-9] c'), pero mi solución actual tampoco las maneja. – Tonio

+0

Es cierto que 'hitEnd()' cumple la misma función que la propia solución del OP de dividir la expresión regular en sucesivos grupos opcionales. Pero todavía no hay forma de detectar una coincidencia parcial que no se alinee con el comienzo de la expresión regular. –

4

Aunque puede haber algunos trucos disponibles, su camino es probablemente el mejor semánticamente. Describe con precisión lo que estás buscando.

Sin embargo, el problema más importante es si realmente necesita validar cada vez que se escribe un carácter en el cuadro de texto. ¿Por qué no puedes validarlo una vez al final y ahorrarte algunos dolores de cabeza?

+0

"Por qué", de hecho ... :(Porque The Client (tm) lo decreta así. El problema con la forma en que lo estoy haciendo, aparte del hecho de que es bastante antipático (tendré que explicarle a los usuarios de la API sobre las extrañas expresiones regulares de correspondencia parcial, etc.), es que no coincidirá con cadenas que coincidan con el FIN de la expresión regular. En el ejemplo anterior, no coincidirá con "3c", que debería ser válido, ya que siempre puede volver atrás y agregar "ab" al principio. – Tonio

+0

¿El cliente realmente especificó que lo tenía que hacer un regex? ¿O es que esa parte particular del diseño proviene del lado técnico? – Yishai

+0

El cliente no especificó que tenía que ser hecho por una expresión regular, esa fue nuestra decisión de diseño. Originalmente se hizo por simple coincidencia de cadenas, pero finalmente decidimos usar expresiones regulares, ya que algunos patrones pueden ser bastante complejos. – Tonio

2

Aquí es una expresión regular que puede resolver el ejemplo particular:

^(?:a|b|[0-9]|c|ab|b[0-9]|[0-9]c|ab[0-9]|b[0-9]c|ab[0-9]c)?$ 

En términos generales, si se puede romper la expresión regular en partes atómicas, que puede o conjuntamente todas las posibles agrupaciones de ellos, pero es grande y feo. En este caso, había 4 partes (a, b, [0-9] yc), por lo que tenía que O juntas 4 + 3 + 2 + 1 = 10 posibilidades. (Para n partes, es (n × (n +1))/2 posibilidades). Es posible que pueda generar esto algorítmicamente, pero sería un gran dolor para probar. Y cualquier cosa compleja (como un subgrupo) sería muy difícil de acertar.

Una solución mejor es, probablemente, simplemente tener un mensaje junto al campo de entrada que indique al usuario "información insuficiente" o algo así, y cuando lo tenga bien, cámbielo a una casilla verde o algo así. Aquí hay un artículo reciente de A List Apart que considera los pros y los contras de los diferentes enfoques de este problema: Inline Validation in Web Forms.

+0

Esto es precisamente lo que estoy tratando de evitar ... expresiones regulares desgarbadas (OR 'en su ejemplo, que contiene subgrupos opcionales al final en mi ejemplo). :( Desafortunadamente, la mejor solución propuesta es inaceptable para el cliente. Lo que requieren es bloquear el ingreso de caracteres ilegales (caracteres con significado ilegal que no conducen a una cadena válida) y comentarios visuales de una cadena válida (es decir, como se implementó, el fondo del cuadro de texto cambia de color cuando la cadena coincide con la expresión regular por completo). – Tonio

+0

Bueno, ¿podría tener dos pasos? uno que ejecuta 'ab [0-9] c' y dice si la cadena completa es válido, y uno que ejecuta la gran expresión regular para decir si lo que han ingresado * podría * ser válido. Puede ejecutar la expresión regular grande en el evento keyPressed, y si eso falla, devuelve falso (es decir, no permita que el usuario ingrese ese personaje) – Kip

+0

Si pudiera generar estas expresiones regulares de forma algorítmica, sería una solución válida. Generarlas para expresiones regulares simples no debería ser un problema, pero desafortunadamente no todas gexps que se utilizan son simples. – Tonio

Cuestiones relacionadas