2010-03-18 17 views
22

He estado utilizando las clases java.util.regex. * Para la Expresión regular en Java y todas buenas hasta ahora. Pero hoy tengo un requisito diferente. Por ejemplo, considere que el patrón es "aabb". Ahora bien, si la cadena de entrada es aa definitivamente no coincidirá, sin embargo, existe la posibilidad de que si anexo bb se convierta en aabb y coincida. Sin embargo, si hubiera comenzado con cc, no importa lo que añada, nunca coincidirá.¿Cómo puedo realizar una coincidencia parcial con java.util.regex. *?

He explorado la clase Pattern y Matcher pero no encontré ninguna forma de lograr esto.

La entrada vendrá del usuario y el sistema tendrá que esperar hasta que el patrón coincida o nunca coincidirá independientemente de cualquier entrada.

¿Alguna pista?

Gracias.

+0

¿Qué regex has encontrado hasta ahora? –

+0

Entonces, para que esto quede claro, ¿está buscando 'continuar con la expresión regular', por así decirlo, desde el punto en que lo dejó (sin rehacer la expresión regular en toda la cadena), en función de la información adicional del usuario? Si es así, eso no es posible, por razones que puedo explicar si confirma esto, a menos que especifique restricciones adicionales. – Cam

+0

Haga que la parte 'bb' sea opcional' aa (bb)? ' – Amarghosh

Respuesta

1

¿Desea saber si una String s coincide con la expresión regular, pero si podría haber una cadena más larga que empiece por s que coincida? Lo sentimos, Regexes no puede ayudarlo porque no tiene acceso al estado interno de la coincidencia; solo obtiene el resultado booleano y cualquier grupo que haya definido, por lo que nunca se sabe por qué falló una coincidencia.

Si está dispuesto a hackear las bibliotecas JDK, puede ampliar (o probablemente teclear) java.util.regex y proporcionar más información sobre el proceso de coincidencia. Si la coincidencia falla porque la entrada se 'agotó', la respuesta sería verdadero; si falló debido a la discriminación de caracteres u otros controles, sería falso. Aunque parece mucho trabajo, porque tu problema es completamente el opuesto de lo que se supone que deben hacer las expresiones regulares.

Otra opción: tal vez sólo tiene que redefinir la tarea de manera que se puede tratar a la entrada como la expresión regular y combinar aabb contra aa * **.? Sin embargo, debes tener cuidado con los metacaracteres de expresiones regulares.

+0

Re su segundo párrafo: Yo diría "Si la coincidencia ha fallado porque la entrada fue 'usada' * en cualquier momento durante el intento de coincidencia *, la respuesta sería verdadera". Después de todo, el motor de expresiones regulares podría haber coincidido hasta el final una vez, luego retroceder y fallar sin tener que volver al final de la cadena. Al igual que cuando se aplica '^ A. * BC $' a 'ABCD'. –

+1

Parece que el método 'hitEnd()' del que Alan Moore escribió hace exactamente eso. Estupendo. –

0

Para el ejemplo que proporcione podría intentar utilizar un antipatrón para descalificar resultados no válidos. Por ejemplo, "^ [^ a]" le diría que su entrada "c ..." no puede coincidir con su patrón de ejemplo de "aabb".

Dependiendo de su patrón, puede dividirlo en patrones más pequeños para verificar y usar múltiples emparejamientos y luego establecer sus límites a medida que ocurre una coincidencia y pasar a la siguiente. Este enfoque puede funcionar, pero si su patrón es complejo y puede tener subpartes de longitud variable, puede terminar volviendo a implementar parte del marcador en su propio código para ajustar los límites posibles de la coincidencia y hacerlo más o menos ambicioso. Una idea general de pseudo-código de esto sería:

boolean match(String input, Matcher[] subpatterns, int matchStart, int matchEnd){ 
    matcher = next matcher in list; 
    int stop = matchend; 
    while(true){ 
    if matcher.matches input from matchstart -> matchend{ 
     if match(input, subpatterns, end of current match, end of string){ 
     return true; 
     }else{ 
     //make this match less greedy 
     stop--; 
     } 
    }else{ 
     //no match 
     return false; 
    } 
    } 
} 

A continuación, puede combinar esta idea con los anti-patrones, y tienen anti-sub-patrones y después de cada partido sub-patrón que comprobar la siguiente anti-patrón, si coincide con que sabe que ha fallado; de lo contrario, continúe el patrón de coincidencia. Es probable que desee devolver algo así como una enumeración en lugar de un booleano (es decir, ALL_MATCHED, PARTIAL_MATCH, ANTI_PATTERN_MATCH, ...)

De nuevo, dependiendo de la complejidad de su patrón real que está tratando de unir escribiendo los sub patrones apropiados/antipatrón puede ser difícil, si no imposible.

-1

Es posible que pueda lograr esto con una máquina de estados (http://en.wikipedia.org/wiki/State_machine). Haga que sus estados/transiciones representen una entrada válida y un estado de error.A continuación, puede alimentar a la máquina de estado con un carácter (posiblemente subcadena según sus datos) a la vez. En cualquier punto puede verificar si su máquina de estado está en el estado de error. Si no está en el estado de error, entonces sabrá que la entrada futura puede coincidir. Si está en el estado de error, entonces sabrá que algo falló anteriormente y cualquier entrada futura no hará que la cadena sea válida.

0

Una forma de hacer esto es analizar su expresión regular en una secuencia de subregexias, y luego volverlas a ensamblar de forma que pueda hacer coincidencias parciales; p.ej. "ab c" tiene 3 subregexiones "a", "b" y "c" que luego puede volver a ensamblar como "a (b * (c)?)?".

Las cosas se vuelven más complicadas cuando la entrada de datos regular contiene alternancia y grupos, pero el mismo enfoque general debería funcionar.

El problema con este enfoque es que la expresión regular resultante es más complicada y podría conducir a un retroceso excesivo para las expresiones complejas de entrada.

0

Si hace que cada carácter de la expresión regular sea opcional y relaje las restricciones de multiplicidad, obtendrá lo que quiera. Por ejemplo, si tiene un patrón coincidente "aa (abc) + bbbb", puede tener un patrón de "coincidencia posible" a? A? (A? B? C?) * B? B? B? B? '.

Esta forma mecánica de producir un posible patrón de coincidencia no cubre construcciones avanzadas como refs hacia delante y hacia atrás.

32

Debería haber mirado más de cerca la API de Matcher; el método hitEnd() funciona exactamente como usted la describe:

import java.util.regex.*; 

public class Test 
{ 
    public static void main(String[] args) throws Exception 
    { 
    String[] ss = { "aabb", "aa", "cc", "aac" }; 
    Pattern p = Pattern.compile("aabb"); 
    Matcher m = p.matcher(""); 

    for (String s : ss) { 
     m.reset(s); 
     if (m.matches()) { 
     System.out.printf("%-4s : match%n", s); 
     } 
     else if (m.hitEnd()) { 
     System.out.printf("%-4s : partial match%n", s); 
     } 
     else { 
     System.out.printf("%-4s : no match%n", s); 
     } 
    } 
    } 
} 

de salida:

aabb : match 
aa : partial match 
cc : no match 
aac : no match 

Por lo que yo sé, Java es el único lenguaje que expone esta funcionalidad. También está el método requireEnd(), que le dice si más entradas podrían convertir una coincidencia en una coincidencia, pero no creo que sea relevante en su caso.

Se agregaron ambos métodos para admitir la clase de escáner, por lo que puede aplicar expresiones regulares a una secuencia sin necesidad de leer toda la secuencia en la memoria.

+2

"Hasta donde yo sé, Java es el único lenguaje que expone esta funcionalidad". - ¿Esto no es equivalente a la coincidencia parcial de Boost? (http://www.boost.org/doc/libs/1_34_1/libs/regex/doc/partial_matches.html) – polygenelubricants

+0

Eso es genial. ¿Puedes probar qué 'hitEnd()' regresa cuando haces coincidir 'ABCD' contra' A. * BC $ '? –

+0

@Tim, obtengo "coincidencia parcial", lo cual tiene sentido, ya que puede agregar "BC" al final y obtener una coincidencia (lo cual hice, y lo hizo). –

10
Pattern p = Pattern.compile(expr); 
Matcher m = p.matcher(string); 
m.find(); 
+0

Ahhhh Estaba usando m.matches(). Derecha. Tiene sentido ahora. – Kieveli

+0

Lo que quería era encontrar el método que permite emparejar parte de la * cadena * a una expresión regular en lugar de viceversa. Este es el método que hará eso – Brandon

Cuestiones relacionadas