2011-02-13 15 views
6

Quiero comprobar si un determinado patrón (por ejemplo, una cadena con comillas dobles) coincide en una posición exacta.Regex coincidente en el desplazamiento exacto

Ejemplo

string text = "aaabbb"; 
Regex regex = new Regex("b+"); 
// Now match regex at exactly char 3 (offset) of text 

me gustaría comprobar si regex partidos en exactamente carbón 3.
yo tuvimos un vistazo a la Regex.Match Method (String, Int32) pero no se comporta como lo que esperaba.
Así que hice algunas pruebas y algunas soluciones:

public void RegexTest2() 
{ 
    Match m; 
    string text = "aaabbb"; 
    int offset = 3; 

    m = new Regex("^a+").Match(text, 0); // lets do a sanity check first 
    Assert.AreEqual(true, m.Success); 
    Assert.AreEqual("aaa", m.Value); // works as expected 

    m = new Regex("^b+").Match(text, offset); 
    Assert.AreEqual(false, m.Success); // this is quite strange... 

    m = new Regex("^.{"+offset+"}(b+)").Match(text); // works, but is not very 'nice' 
    Assert.AreEqual(true, m.Success); 
    Assert.AreEqual("bbb", m.Groups[1].Value); 

    m = new Regex("^b+").Match(text.Substring(offset)); // works too, but 
    Assert.AreEqual(true, m.Success); 
    Assert.AreEqual("bbb", m.Value); 
} 

De hecho estoy empezando a creer que se new Regex("^.", 1).Match(myString)no coincidir con cualquier cosa.

¿Alguna sugerencia?

Editar:

que tiene una solución de trabajo (solución). Entonces mi pregunta es acerca de la velocidad y una buena implementación.

Respuesta

8

¿Has probado lo que dice docs?

Si desea restringir un partido tan que comienza en una posición carácter particular en la cadena y el motor de expresiones regulares no escanear el resto de la cadena para un partido , anclar la regularidad expresión con una \ G (a la izquierda para un patrón de izquierda a derecha , o en la derecha para un patrón de derecha a izquierda). Este restringe la coincidencia, por lo que debe iniciarse en exactamente al inicio.

i.e.reemplazar el ^ con un \G:

m = new Regex(@"\Gb+").Match(text, offset); 
Assert.AreEqual(true, m.Success); // should now work 
+0

¡Muy buena idea! –

+0

Batirme por 8 segundos, me demoré demasiado para confirmar ': P'. '\ G' es correcto aquí, pero agregaría una advertencia sobre el uso del mismo objeto' Regex', suponiendo que el OP no creará uno nuevo cada vez. No estoy muy seguro de cómo se comportaría, pero puede recordar la última posición, incluso con el desplazamiento. Vale la pena comprobarlo. (De nuevo, no estoy seguro) – Kobi

+0

@Kobi - Sospecho que este puede ser el caso solo si usa m.MatchNext(), no si vuelve a llamar a Match() en el mismo objeto Regex. – CAFxX

0

Puede añadir una aserción hacia atrás positivo ((?<=...)) a su expresión regular:

Regex regex = new Regex("(?<=\A.{3})b+"); 

Esto asegura que hay exactamente tres caracteres (.{3}) después del inicio de la cadena (\A) y antes del inicio de la expresión regular También puede usar ^ en lugar de \A, pero dado que el primero también puede significar (en algunas circunstancias) "Coincidencia al comienzo de una línea", este último es un poco más explícito.

Puede que necesite compilar la expresión regular usando RegexOptions.Singleline para permitir que el punto también coincida con los caracteres de nueva línea si eso es un requisito.

Por cierto,

m = new Regex("^b+").Match(text, 3); 

no funciona porque ^ partidos en el inicio de la línea, y la posición antes de la primera b es, por supuesto, no al comienzo de la línea.

+0

lo siento, me olvidé de mencionar, que el desplazamiento de '3' es una variable. ¿No disminuirá el rendimiento dramáticamente si construí una nueva expresión regular para cada llamada? –

+0

Bueno, en ese caso, recomendaría el uso de 'Substring' para obtener primero la parte relevante de su cadena y luego desatar la furia de las expresiones regulares sobre el resto. –

+1

¿No es tan lento si la cadena con la que se va a emparejar es muy larga? –

1

Se esperan a Match(text, offset)inicio evaluar la cadena buscada como si estuviera a partir del offset. Esto no es asi ^ realmente evaluará para compensar 0, no offset!

a fin de utilizar el overload of Match que evaluará ^ a offset:

m = new Regex("^bbb$").Match(text, offset, text.Length-offset); 

otra opción sería utilizar, pero es más lento que el de arriba:

m = new Regex("^.{"+offset+"}bbb$").Match(text); 

o esto (el primer método es el más rápido):

m = new Regex(@"\Gbbb$").Match(text, offset); 
Cuestiones relacionadas