2011-12-22 28 views
16

Esto debería ser una pregunta de expresiones regulares bastante simple pero no pude encontrar ninguna respuesta en ningún lado. ¿Cómo se podría hacer una expresión regular, que coincida con SÓLO 2 caracteres o al menos 4 caracteres? Aquí está mi actual método de hacerlo (ignorar la expresión regular en sí, que es además el punto):regex para n caracteres o al menos m caracteres

[A-Za-z0_9_]{2}|[A-Za-z0_9_]{4,} 

Sin embargo, este método toma el doble de tiempo (y es de aproximadamente 0,3 segundos más lento para mí en un archivo de 400 líneas) , entonces me preguntaba si había una mejor manera de hacerlo.

Respuesta

14

Optimizar el comienzo y anclarlo.

^[A-Za-z0-9_]{2}(?:|[A-Za-z0-9_]{2,})$ 

(También, se les había dicho que ignorar la expresión regular en sí, pero supuse que probablemente quería 0-9, no 0_9)

EDITAR Hm, yo estaba seguro leí que desea hacer coincidir líneas. Retire los anclajes (^$) si desea hacer coincidir también dentro de la línea. Si solo hace coincidir líneas completas, los anclajes le acelerarán (bueno, el ancla delantera ^ lo hará, al menos).

+0

Esto funciona perfectamente bien. Y solo quiero hacer coincidir el comienzo de una línea, así que me quedaré con el ^. – david

3

Su solución se ve bastante bien. Como alternativa, se puede intentar algo bajo esa manera:

[A-Za-z0-9_]{2}(?:[A-Za-z0-9_]{2,})? 

Por cierto, creo que quieres guión en lugar de guión bajo entre 0 y 9, ¿verdad?

+0

Sí, quise utilizar un guión en lugar de un guión bajo entre 0 y 9. Por cierto, ¿qué significa "?:" En tu expresión regular? – david

+0

@ david-'?:' Significa que la expresión entre paréntesis no se captura. Revisa este sitio si no sabes lo que quiero decir con eso: http://www.regular-expressions.info/brackets.html – dlras2

+0

@david, es para un grupo que no captura como se dijo anteriormente y es más eficiente que regular grupo. –

-1

así que básicamente que desea hacer coincidir palabras de longitud 2 o 2 + 2 + N, N> = 0

([A-Za-z0-9][A-Za-z0-9](?:[A-Za-z0-9][A0Za-z0-9])*) 

ejemplo de trabajo:

#!/usr/bin/perl 

while (<STDIN>) 
{ 
    chomp; 
    my @matches = ($_=~/([A-Za-z0-9][A-Za-z0-9](?:[A-Za-z0-9][A0Za-z0-9])*)/g); 
    for my $m (@matches) { 
     print "match: $m\n"; 
    } 
} 

archivo de entrada:

cat in.txt 
ab abc bcad a as asdfa 
aboioioi i i abc bcad a as asdfa 

salida:

perl t.pl <in.txt 
match: ab 
match: ab 
match: bcad 
match: as 
match: asdf 
match: aboioioi 
match: ab 
match: bcad 
match: as 
match: asdf 
+1

-1, como A) me duele ver expresiones duplicadas en lugar de '{n}', y B) su solución solo captura cadenas de longitud par (y aun así no lo hace de manera particularmente eficiente) – dlras2

+0

A) no comenten, B) tienen buen ojo, gracias por notar el error. – user237419

+0

Por curiosidad, ¿por qué la preferencia hacia la repetición? – dlras2

1

La solución que presenta es correcta.

Si está tratando de optimizar la rutina, y el número de cadenas de coincidencias que coinciden con 2 o más caracteres es mucho menor que las que no lo hacen, considere aceptar todas las cadenas de longitud 2 o superior, y luego lanzarlas si re de longitud 3. Esto puede aumentar el rendimiento al solo verificar la expresión regular una vez, y la segunda llamada ni siquiera necesita ser una expresión regular; verificar una longitud de cuerda generalmente es una operación extremadamente rápida.

Como siempre, realmente necesita ejecutar pruebas en datos del mundo real para verificar si esto le daría un aumento de velocidad.

+0

Muy bien, gracias por la sugerencia. Probaré tu método. Parece una buena idea. – david

Cuestiones relacionadas