2010-06-27 40 views
6

Estoy tratando de usar expresiones regulares para determinar qué formato ha aplicado el usuario al ingresar una entrada en un cuadro de texto.
Las expresiones regulares son los siguientes:¿Por qué estas expresiones regulares se ejecutan lentamente en Java?

(\\s?[" + alphabet + "]{9,9})+ 

Para determinar si la entrada es una o más cadenas de longitud 9 en un alfabeto determinado, posiblemente separadas por espacios en blanco.

(>[\\w\\s]+\\n[" + alphabet + "\\s]+)+ 

para comprobar si la entrada está en FASTA format

Las expresiones regulares se ejecutan terriblemente lento cuando se compara con . ¿Por qué es esto?

Pensé que esto podría deberse a que Java almacena todas las coincidencias potenciales (que no necesito en este momento), pero agregar ?: en cada paréntesis rompe la expresión regular. ¿Cómo debe hacerse esto?

Gracias,

Martin

Edición 1: he podido reproducir este problema - que sólo ocurre en un ordenador. Esto podría sugerir algo incorrecto con esa configuración particular de máquina virtual.
Necesitamos algo más sólido, por lo que implementaremos esto de manera diferente. Elegí la respuesta de Joel como la correcta, ya que creo que algún caso especial en Pattern podría ser la causa.

+0

¿Cuántos patrones está tratando de hacer coincidir con cada cadena de entrada? ¿Los patrones son dinámicos o estáticos? –

+0

@Joel Solo existen estos dos patrones. Ellos son estáticos. El uso de String.matches provocará una compilación cada vez, pero incluso si se compara con los patrones, una sola vez lleva mucho tiempo (> 10s para una entrada de aproximadamente 300 caracteres) –

+0

¿se puede definir "terriblemente lento"? –

Respuesta

0

Si tiene varios patrones diferentes de expresiones regulares que coinciden con la misma entrada para tratar de categorizar la entrada, entonces es probable que sea mejor utilizar un generador de analizador léxico como JFlex.

Se pueden encontrar otras herramientas analíticas y analíticas léxicas basadas en Java que normalmente se usan en la construcción de compiladores, listadas here.

+0

Esas son herramientas útiles, ¡gracias! Pero solo tengo 2 expresiones regulares, y esto debería ser muy simple: creo que usar JFlex y similares sería exagerado. –

+0

@Martin - Parece que JFlex o similar sería más de lo que normalmente se necesita en este caso. Sin embargo, al observar más de cerca las expresiones regulares que está utilizando, es posible que su caso exponga algún caso degenerado en cómo la clase Pattern compila su analizador. Puede valer la pena probar JFlex solo para ver si puede producir un analizador más ajustado para este escenario. –

1

string.matches() compila la expresión regular cada vez que lo haces. En su lugar, observe las clases Pattern/Matcher, que le permiten almacenar en caché las expresiones regulares precompiladas.

Otra cosa es utilizar grupos regex no capturados si no necesita el resultado de la coincidencia.

+0

Solo llamo a matches() una vez, por lo que no debería ser un problema. Las expresiones regulares funcionan bien con una entrada pequeña, pero horrendamente lentamente con la entrada de más de, digamos, 200 caracteres. No pude conseguir grupos que no capturaran, ¿puede dar un ejemplo? –

+0

Cambiar a grupos que no capturan no le dará un factor de mejora de 1000. Aún así, esta es la forma en que lo haces - ¿poner?: Después del paréntesis de apertura - ejemplo: (?: \\ s? ["+ Alphabet +"] {9,9}) + – ddimitrov

1

esto podría no explicar su problema en particular. pero una vez que me sumergí en la implementación de expresiones regulares de JDK, y me sorprendió ver cómo no es sofisticado. en realidad no construye una máquina de estado que avance en cada char de entrada. Supongo que tienen sus razones.

En su caso, es tan fácil escribir un análisis usted mismo, a mano. la gente teme hacer eso, parece "tonto" codificar manualmente estos pequeños pasos, y la gente piensa que las bibliotecas establecidas deben estar haciendo algunos trucos espléndidos para superar las soluciones locales. eso no es cierto. en muchos casos, nuestras necesidades son bastante simples, y es más simple y más rápido para hacer bricolaje.

+0

El método Pattern.compile() crea máquina de estado de los descendientes de la clase Pattern.Node. ¿Quiere decir que construye un autómata de NFA en lugar de DFA? Ese es el diseño utilizado por la mayoría de los motores de expresiones regulares ricos en características, la velocidad de negociación para las características. Aquí hay un artículo explicando esto y sugiriendo una alternativa: http://weblogs.java.net/blog/2006/03/27/faster-java-regex-package – ddimitrov

Cuestiones relacionadas