2011-05-18 8 views
8

Por lo tanto, estoy digiriendo una secuencia de proteína con una enzima (por su curiosidad, Asp-N) que se escinde antes de las proteínas codificadas por B o D en una secuencia codificada de una sola letra. Mi análisis real usa String#scan para las capturas. Estoy tratando de averiguar por qué la siguiente expresión regular no se digiere correctamente ...Digestión de proteína Regex

(\w*?)(?=[BD])|(.*\b) 

donde existe el antecedente (.*\b) para capturar el final de la secuencia. Para :

MTMDKPSQYDKIEAELQDICNDVLELLDSKGDYFRYLSEVASGDN 

Esto debería dar algo como: [MTM, DKPSQY, DKIEAELQ, DICN, DVLELL, DSKG, ... ] sino que se pierde cada D en la secuencia.

He estado usando http://www.rubular.com para la solución de problemas, que se ejecuta en 1.8.7 aunque también he probado este REGEX en 1.9.2 en vano. Tengo entendido que las aserciones de búsqueda de ancho cero son compatibles con ambas versiones de ruby. ¿Qué estoy haciendo mal con mi expresión regular?

+0

¿Qué método estás usando? 'String # scan',' String # split' u otra cosa? –

+3

+1 Qué gran pregunta. No esperaba los resultados que obtuve, y el análisis posterior me enseñó algo acerca de la forma en que la expresión regular maneja las repetidas coincidencias de ancho cero. – Phrogz

+0

Estoy un poco confundido por su afirmación "que se escinde antes que las proteínas codificadas por B o D". Según entiendo las cosas, ** B ** es el código de una sola letra para ** bien ** D o N (donde no se sabe si el residuo es Asp o Asn). ¿Puede Asp-N escindirse antes de Asn? – tomd

Respuesta

3

da la forma más sencilla de apoyar este es dividir en la búsqueda hacia delante de anchura cero:

s = "MTMDKPSQYDKIEAELQDICNDVLELLDSKG" 
p s.split /(?=[BD])/ 
#=> ["MTM", "DKPSQY", "DKIEAELQ", "DICN", "DVLELL", "DSKG"] 

Para la comprensión de lo que estaba pasando mal con su solución , veamos primero su expresión regular versus una que funcione:

p s.scan(/.*?(?=[BD]|$)/) 
#=> ["MTM", "", "KPSQY", "", "KIEAELQ", "", "ICN", "", "VLELL", "", "SKG", ""] 

p s.scan(/.+?(?=[BD]|$)/) 
#=> ["MTM", "DKPSQY", "DKIEAELQ", "DICN", "DVLELL", "DSKG"] 

El problema es que si puede capturar cero caracteres y seguir coincidiendo con su búsqueda anticipada de ancho cero, tendrá éxito sin avanzar el puntero de exploración. Veamos un caso de prueba más simple, pero-similares:

s = "abcd" 
p s.scan //  # Match any position, without advancing 
#=> ["", "", "", "", ""] 

p s.scan /(?=.)/ # Anywhere that is followed by a character, without advancing 
#=> ["", "", "", ""] 

Una implementación ingenua de String#scan podría quedar atrapado en un bucle infinito, a juego en varias ocasiones con el puntero antes de que el primer carácter. Parece que una vez que se produce una coincidencia sin avanzar el puntero, el algoritmo avanza a la fuerza el puntero por un carácter. Esto explica los resultados en su caso:

  1. Primero coincide con todos los caracteres hasta un B o D,
  2. entonces concuerda con la posición de anchura cero justo antes de la B o D, sin mover el puntero del carácter ,
  3. Como resultado, el algoritmo mueve el puntero más allá de B o D, y continúa después de eso.
+0

Quizás debería simplificar, ya que la otra respuesta parece funcionar, pero esto es realmente lo que estaba buscando: ¡Comprensión! ¡Gracias por explicarme por qué se rompió mi expresión regular! – Ryanmt

+0

@Ryanmt Me alegro de poder ayudar. También modifiqué mi expresión regular para mostrarle una forma más sencilla de capturar el final de la secuencia si quería usar esto en lugar de la solución más simple basada en divisiones. – Phrogz

+0

Ah. He leído sobre eso pero no lo he aplicado a mi problema. ¡Gracias! – Ryanmt

9

Básicamente, ¿quieres cortarte la cuerda antes de cada B o D?

"...".split(/(?=[BD])/) 

que

["MTM", "DKPSQY", "DKIEAELQ", "DICN", "DVLELL", "DSKG", "DYFRYLSEVASG", "DN"] 
+0

Excelente respuesta y limpieza. ¡Gracias! – Ryanmt