class: center, middle, inverse, title-slide # 9. Expresiones regulares ### Ana BVA ### 02 June, 2021 --- # Patrones en biología ¿Qué patrones en biología conoces? Ex. `ATG` codón de inicio de la transcripción --- # Patrones en bioinformática ¿Qué patrones tenemos en bioinformática? --- # Patrones en genes Recordando la tarea de condicionales: `Genes: kdy647, jdg766, kdy533, hdt739, hdu045, teg436` -- .content-box-blue[ - Imprima los nombres de los genes de todos los genes cuyo nombre comience con "k" o "h" ] -- ¿Qué patrones hay en los genes? --- # Expresiones regulares En cómputo teórico y teoría de lenguajes formales, una expresión regular, o expresión racional, también son conocidas como regex o regexp, por *regular expression*, **es una secuencia de caracteres que conforma un patrón de búsqueda**. - [Wikipedia](https://es.wikipedia.org/wiki/Expresi%C3%B3n_regular#:~:text=En%20c%C3%B3mputo%20te%C3%B3rico%20y%20teor%C3%ADa,conforma%20un%20patr%C3%B3n%20de%20b%C3%BAsqueda.) -- Es todo un tema en programación: <img src="https://images-na.ssl-images-amazon.com/images/I/51QMf2mTyBL._AC_UL600_SR366,600_.jpg" width="250px" style="display: block; margin: auto;" /> --- # Expresiones regulares en Python Python maneja *regexp* pero desde el módulo `re`. ```python import re ``` -- Anteriormente vimos caracteres especiales como `\n` (salto de línea) o `\t` (tabular). ```python print("\t\n") ``` -- A veces los caracteres especiales chocan con caracteres que ya tienen significado en Python. Para que Python ignore estos caracteres, podemos ocupar `r` (*raw*), y cualquier caracter especial dentro del *string* se ignorará. -- ```python print(r"\t\n") ``` --- # Busqueda de patrones en un *string* ¿Cómo buscar `GAATTC` en `ATCGCGAATTCAC`? -- <br> .center[.content-box-green[**Vamos a pyCharm**]] --- # Busqueda de patrones en un *string* ¿Cómo buscar `GGACC` en `ATCGCGAATTCACGGACC` usando el módulo `re`? -- Con el módulo de `re` podemos usar `search`. ```python import re re.search("GGACC","ATCGCGAATTCACGGACC") ``` -- En caso de requerirlo, podemos agregar `r`. --- # Busqueda de patrones en un *string* Podemos ocupar condicionales para buscar más patrones en una secuencia. -- ¿Cómo sería para buscar `GGACC` o `GGTCC`? ```python dna = "ATCGCGAATTCACGGACC" ``` -- <br> .center[.content-box-green[**Vamos a pyCharm**]] --- class: inverse, center, middle # Caracteres --- # Regexp Si vemos el patrón: `GGxCC` es igual y solo cambia `A` o `T`. -- Lo podemos describirlo como: `GG(A|T)CC`, escribiendo las posibilidades en `()` y separando las opciones por un `|`. -- ```python dna = "ATCGCGAATTCACGGACC" if re.search(r"GG(A|T)CC", dna): print("site found!") ``` -- Otra forma de escribirlo es: ```python dna = "ATCGCGAATTCACGGACC" if re.search(r"GG[AT]CC", dna): print("site found!") ``` --- # Regexp `.` `.` el uso de un punto representa **cualquier caracter**. -- Si `x` en el patrón `GGxCC` puede ser cualquier caracter, se puede escribir como: ```python dna = "ATCGCGAATTCACGGACC" if re.search(r"GG.CC", dna): print("site found!") ``` -- Pero también identificará caracteres diferentes a `ATGC`, como `n, $`, etc. ```python dna = "ATCGCGAATTCACGGnCC" ``` --- # Regex `[^]` (negación) Para negar caracteres podemos usar `[^]`. Si queremos cualquier bp `ATGC`, se puede indicar con: ```python dna = "ATCGCGAATTCACGGnCC" if re.search(r"[^ATGC]", dna): print("ambiguous base found!") ``` -- ¿Cómo podemos generar un error si eso ocurre? (Tip: `raise`) -- <br> .center[.content-box-green[**Vamos a pyCharm**]] --- class: inverse, center, middle # Cuantificadores --- # Regexp `?` El símbolo `?` identifica cero o una vez el caracter. -- En `GAT?C`, la `T` es opcional. -- Podemos pedir que sea un grupo de caracteres sea opcional: `GGG(AAA)?TTT`, buscará `GGGAAATTT` o `GGGTTT`. ```python dna = "GGGTTT" if re.search(r"GGG(AAA)?TTT", dna): print("found!") ``` --- # Regexp `+` El símbolo `+` identifica una o más vez el caracter. -- `GGGA+TTT` buscará `GGGATTT` o `GGGAATTT` o `GGGAAATTT`, etc. PERO NO o `GGGTTT` ```python dna = "GGGAATTT" if re.search(r"GGGA+TTT", dna): print("found!") ``` --- # Regexp `*` El símbolo `*` indica que es opcional pero también puede estar repetido. -- `GGGA*TTT` buscará `GGGTTT` o `GGGATTT` o `GGGAATTT` o `GGGAAATTT`, etc. ```python dna = "GGGTTT" if re.search(r"GGGA*TTT", dna): print("found!") ``` --- # Regexp `*` Si queremos especificar el número de repetidos usamos `{5}`. -- `GA{5}T` buscará `GAAAAAT` PERO NO `GAAAAT` o `GAAT` o `GAT`, etc. -- Podemos especificar un rango `{2,4}` `GA{2,4}T` buscará `GAAAAT` o `GAAAT` o `GAAT` PERO NO `GAAAAT` o `GAT`. -- `{5,}` Indica 5 ó más. ```python dna = "GGGAAATTT" if re.search(r"GGGA{2,4}TTT", dna): print("found!") ``` --- class: inverse, center, middle # Posición --- # Regexp: Posición Anteriormente vimos: `[^]` que nos sirve para negar. Ejemplo `[^ATGC]`. Ahora veremos como usarlo para indicar posición. -- - El símbolo `^` indica el inicio. `^AAA` identifica `AAATTT` PERO NO `GGGAAATTT` -- - El símbolo `$` indica el final. `GGG$` identifica `AAAGGG` PERO NO `AAAGGGTTT`. ```python dna = "AAATTT" if re.search(r"^AAA", dna): print("found!") ``` --- class: inverse, center, middle # Combinar --- # Regexp <img src="https://miro.medium.com/max/1838/1*hjsbL45MhT2Tw5DGAYoAUg.png" width="550px" style="display: block; margin: auto;" /> --- # Regexp: Combinar ¿Qué se busca con la siguiente expresión? `^AUG[AUGC]{30,1000}A{5,10}$` --- class: inverse, center, middle # Métodos de re --- # Extraer la información ¿Qué tipo de clase resulta de `re.search()`? -- ```python type(re.search(r"[^ATGC]", dna)) ``` -- Podemos usar el método `group()` para obtener el patrón deseado ```python dna = "ATCGCGAATTCACGGnCC" m = re.search(r"[^ATGC]", dna) if m: print("ambiguous base found!") ambig = m.group() print("the base is " + ambig) ``` --- ## Ejercicio: Función que verifique que la secuencia .content-box-blue[ - Crea una función que verifique que la secuencia tenga [ATGC] - Que arroje error si no es [ATGC] y que muestre los caracteres incorrectos. ] ``` dna = "ATCGCGAATTCACGGnCC" ``` --- # Extraer la información ¿Qué se busca con la siguiente expresión? `.+ .+` --- # Extraer la información Para guardar la información en variables separadas podemos usar `()` `(.+) (.+)` -- ```python scientific_name = "Homo sapiens" m = re.search(r"(.+) (.+)", scientific_name) if m: genus = m.group(1) species = m.group(2) print("genus is " + genus + ", species is " + species) ``` --- # Extraer la posición Podemos extraer la posición en la que se encuentra el string buscado con `start()`. - Recuerda que Python cuenta desde cero ```python dna = "CGATnCGAACGATC" m = re.search(r"[^ATGC]", dna) if m: print("ambiguous base found!") print("at position " + str(m.start())) ``` --- # Múltiples matches Para identificar varios casos podemos ocupar `finditer()` que regresa una lista de los matches identificados. ```python dna = "CGCTCnTAGATGCGCrATGACTGCAyTGC" matches = re.finditer(r"[^ATGC]", dna) for m in matches: base = m.group() pos = m.start() print(base + " found at position " + str(pos)) ``` --- # Múltiples matches También podemos ocupar `findall()` para extraer la información. ```python dna = "CGCTCnTAGATGCGCrATGACTGCAyTGC" result = re.findall(r"[^ATGC]", dna) print(result) ``` --- ## Ejercicio: Regiones de AT .content-box-blue[ Encuentra las regiones que tengan más de 5 As o Ts ] ``` dna = "CTGCATTATATCGTACGAAATTATACGCGCG" ``` --- # Dividir También podemos dividir el string con `re.split()` ```python dna = "CGCTCnTAGATGCGCrATGACTGCAyTGC" result = re.split(r"[^ATGC]", dna) print(result) ``` --- ## Ejercicio: Función que verifique que la secuencia .content-box-blue[ - Crea una función que verifique que la secuencia tenga [ATGC] - Que arroje error si no es [ATGC] y que muestre los caracteres incorrectos. - Usa `try/except` para manejo de errores - Sino tiene otros caracteres que imprima las regiones ricas en AT ] ``` dna = "CTGCATTATATCGTACGAAATTATACGCGCG" ```