2009-01-06 11 views
13

En Javascript he definido una expresión regular y ahora un usuario está escribiendo una cadena. Quiero decirle si su cadena todavía podría coincidir con RegExp si continúa escribiendo o si ya está en el camino equivocado. Por ejemplo:Compruebe si string es un prefijo de un Javascript RegExp

var re = /a*b/; 

"a".isPrefixOf(re); // true 
"x".isPrefixOf(re); // false 

¿Cómo es posible una implementación de isPrefixOf parece?

Actualización: Gracias por sus respuestas, hacer la expresión regular a prueba de prefijos, como lo sugiere brad, parece ser una buena solución. Pero todavía estoy tratando de encontrar una solución general.

Quizás de esta manera: Creamos una nueva expresión regular con la entrada del usuario seguida de .*. Esta expresión regular describe todas las palabras que el usuario aún puede ingresar. Si la intersección de esta expresión regular creada y la expresión regular original está vacía, entonces el usuario ya está en el camino equivocado. Si no es así, él está bien. Por ejemplo:

var re = /a*b/; 
var sInput = "a"; 
var reInput = new RegExp(sInput + ".*"); 

reIntersection = re.intersect(reInput); 
reIntersection.isEmpty(); // false 

intersect() devuelve una nueva expresión regular que sólo acepta palabra que tanto re y reInput aceptarían. La función no existe todavía, pero podemos hacerlo operativo de preanálisis:

RegExp.prototype.intersect = function(pattern2) { 
    return new RegExp('(?=' + this.source + ')' + pattern2.source); 
} 

Lo que queda abierta es la función isEmpty(). ¿Cómo podríamos comprobar si una expresión regular de JavaScript coincide con una palabra o si está vacía?

Respuesta

-1

Primero define su expresión regular como: var re = new RegExp (/^(regexp aquí) $ /);

en el caso onkeypress, marca la expresión regular como esto:

text.match (regexp) - donde el texto es la cadena introducida.

¿Esto es claro?

+1

Debe leer la pregunta con más cuidado. No pregunta cómo llamar al emparejador. Pregunta cómo escribir el marcador. – user51568

-1

Una forma de hacer esto podría ser enganchar al evento onKeyUp de un cuadro de texto y .test el texto contra la expresión regular. Mi suposición es, por supuesto, que desea hacer una coincidencia de expresiones regulares. no estoy seguro si esto es exactamente lo que necesita, de hecho, su código:

"a".isPrefixOf(re); // true 

nunca coinciden, ya que está obligado a tener también un carácter posterior "b" (es posible que desee modificar el normal expresión). Por ejemplo, este código pondrá a prueba en contra de cualquier cadena coincidente este formato:

a-n(n)-b 

Aquí está el código, guardarlo como una página y se carga en el navegador:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="it"> 
<body> 
    <input type="text" size="20" id="txtData" onkeyup="showResult()" /> 
    <div id="dvResult" /> 
</body> 
</html> 
<script type="text/javascript"> 
//<![CDATA[ 

    theRegExp = /^a\-\d{1,2}\-b$/; 

    function isPrefixOf(aText, aRegExp) 
    { 
     return aRegExp.test(aText); 
    } 

    function showResult() 
    { 
     res = document.getElementById("dvResult"); 
     res.innerHTML = isPrefixOf(document.getElementById("txtData").value, theRegExp) ? "Correct" : "Bad input"; 
    } 

//]]> 
</script> 
+0

Debe leer la pregunta con más cuidado. No pregunta cómo llamar al emparejador. Pregunta cómo escribir el marcador. – user51568

+0

¡Es por eso que destaqué esa nota en negrita! – Manuel

+0

Si bien la pregunta pudo haber sido mejor redactada, creo que no es difícil de entender. ¿Qué voto quieres que elimine? – user51568

2

pregunta muy interesante. En mi búsqueda rápida, no encontré nada predefinido (ni siquiera en Perl) que resuelva este problema.

EDITAR: Ouch, parece que Java tiene algo similar llamado hitEnd() - ver la respuesta de Alan M. Lo que hace HitEnd() es decir que el resultado de match() (verdadero o falso) puede ser modificado por una entrada adicional.El libro "Mastering Regular Expressions" dice que no es muy confiable (no estoy seguro por qué, la página 392 no está disponible en google books).

Dependiendo de las características de las expresiones regulares que uses, un truco rápido como escribir algún tipo de prefijos de la expresión regular:

por ejemplo para un + * b + c sus prefijos serán una:.

 
a+ 
a+a* 
a+a*b+ 
a+a*b+c 

e intentar coincidir con alguno de ellos con su cadena podría funcionar Este truco rápido se hace difícil si use el operador de elección, si usa el operador de rango {n, m} o referencias retrospectivas.

Habiendo dicho eso, creo que la buena solución es modificar ligeramente el algoritmo de coincidencia.

El algoritmo de coincidencia normalmente empleado es un algoritmo de retroceso (que funciona bien en la práctica, incluso si el peor de los casos es exponencial). Este algoritmo finaliza exitosamente siempre que ha llegado al final de la expresión regular (incluso si no se consumió toda la cadena). Lo que debe hacer es modificar la condición de terminación de manera que también termine exitosamente cuando haya consumido toda la entrada.

Habiendo dicho esto, probablemente tendrías que implementar el algoritmo en JavaScript. Esperemos que esto se convierta en parte de bibliotecas como Jquery.

Para más referencias y la teoría sobre el algoritmo, compruebe este artículo Salida:

http://swtch.com/~rsc/regexp/regexp1.html

(incluso si se hace una demanda contra el algoritmo de retroceso y sugiere un algoritmo basado en FA (pero el FA no puede manejar retros referencias)).

3

Creo que su mejor opción aquí es hacer su Regex a prueba de prefijos. Para el ejemplo que dio, /a*b/, creo que probablemente pueda usar /a*b?/.test(userinput). Para patrones más complejos, esto podría ser cada vez más difícil, pero aún creo que se puede hacer anidando cada subexpresión en una serie de cuantificadores opcionales (?). Por ejemplo:

/a*bcd*e/ 

La expresión regular prefijo podría ser:

/a*(b(c(d*e?)?)?)?/ 

Es un poco desordenado, pero va a resolver su problema bastante bien, creo.

+0

Esta es una gran idea (se obtiene un voto positivo), pero se rompe rápidamente para patrones más complejos, creo. ¿Cómo crearías un prefijo regex para el siguiente patrón?/a (bc | BC) d/ – Prestaul

4

Parece que las personas se dividen de forma pareja en la forma en que interpretan esta pregunta, por lo que voy a demostrar el concepto con un ejemplo de Java.

import java.util.regex.*; 

public class Test 
{ 

    public static void main(String[] args) throws Exception 
    { 
    tryMatch("^a*b+$", "a", "ab", "abc"); 
    } 

    public static void tryMatch(String regex, String... targets) 
    { 
    Pattern p = Pattern.compile(regex); 
    Matcher m = p.matcher(""); 
    System.out.printf("%nregex: %s%n", regex); 
    System.out.printf("target | matches() | hitEnd()%n"); 
    for (String str : targets) 
    { 
     m.reset(str); 
     System.out.printf("%-6s | %-9B | %-9B%n", 
      str, m.matches(), m.hitEnd()); 
    } 
    } 
} 

de salida:

regex: ^a*b+$ 
target | matches() | hitEnd() 
a  | FALSE  | TRUE 
ab  | TRUE  | TRUE 
abc | FALSE  | FALSE 

cadena de destino "a" no coincide con la expresión regular, porque requiere al menos un b, pero podría ser el prefijo de una persona compatible, por lo que vuelve hitEnd()true. La cadena "ab" tiene todo lo que se necesita para una coincidencia, pero también coincidiría si agregamos más b al final, por lo que hitEnd() aún devuelve true. Con "abc" el intento de coincidencia falla antes de que llegue al final de la cadena objetivo, por lo que la expresión regular no puede coincidir con ninguna cadena que comience con "abc".

Por lo que sé, Javascript no tiene nada como el método hitEnd() de Java, pero podría ser posible simularlo. Si alguien sabe cómo, será Flagrant Badass, Steven Levithan.

+0

upvoted para obtener una buena referencia de hitEnd – user51568

Cuestiones relacionadas