Saltar al contenido principal
LibreTexts Español

1.11: Patrones (Expresiones Regulares)

  • Page ID
    55196
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    \( \newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\)

    ( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\id}{\mathrm{id}}\)

    \( \newcommand{\Span}{\mathrm{span}}\)

    \( \newcommand{\kernel}{\mathrm{null}\,}\)

    \( \newcommand{\range}{\mathrm{range}\,}\)

    \( \newcommand{\RealPart}{\mathrm{Re}}\)

    \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\)

    \( \newcommand{\Argument}{\mathrm{Arg}}\)

    \( \newcommand{\norm}[1]{\| #1 \|}\)

    \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\)

    \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    \( \newcommand{\vectorA}[1]{\vec{#1}}      % arrow\)

    \( \newcommand{\vectorAt}[1]{\vec{\text{#1}}}      % arrow\)

    \( \newcommand{\vectorB}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vectorC}[1]{\textbf{#1}} \)

    \( \newcommand{\vectorD}[1]{\overrightarrow{#1}} \)

    \( \newcommand{\vectorDt}[1]{\overrightarrow{\text{#1}}} \)

    \( \newcommand{\vectE}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash{\mathbf {#1}}}} \)

    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \)

    \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)

    En capítulos anteriores, utilizamos un sencillo programa fasta_stats para realizar análisis básicos en un archivo FASTA llamado Pz_CDNAS.FASTA, principalmente como excusa para aprender sobre los flujos estándar y herramientas como grep y ordenar. Resulta que la información en el archivo Pz_CDNAS.fasta nos proporciona muchas preguntas potenciales para reflexionar.

    Las secuencias en este archivo son en realidad un subconjunto de transcripciones putativas, producidas a partir de un ensamblaje de transcriptoma de novo para la mariposa Papilio zelicaon. Cada línea de cabecera de secuencia codifica una variedad de información: la segunda y tercera columnas de las líneas de cabecera revelan el número de lecturas que contribuyen a cada secuencia ensamblada y la cobertura promedio de la secuencia (definida como el número total de bases aportadas por lecturas, dividido por la secuencia ensamblada longitud). Incluso los ID de secuencia codifican cierta información: todos comienzan con un identificador pseudoaleatorios, pero algunos tienen un sufijo como _TY.

    I.11_1_UNIX_133_PZ_CDNAS_Less

    Los grupos de secuencias que comparten el mismo sufijo _ se identificaron previamente como que tenían coincidencias compartidas usando un Self-blast. Los ID de secuencia sin dicho sufijo no tenían coincidencias. Podríamos preguntarnos: ¿cuántas secuencias hay en tal grupo? Esto podría responderse fácilmente usando primero grep para extraer líneas que coincidan con > (las líneas de encabezado), y luego usando otro grep para extraer aquellas con el patrón _ (las de un grupo) antes de enviar el resultado a wc.

    Una pregunta más compleja sería preguntar cuántos grupos diferentes están representados en el archivo. Si la información del grupo se almacenaba en una columna separada (digamos, la segunda columna), esta pregunta podría responderse con el mismo proceso anterior, seguida de un sort -k2,2d -u para eliminar identificadores de grupo duplicados. Pero, ¿cómo podemos coaccionar la información del grupo en su propia columna? Esto podríamos hacer sustituyendo instancias de _ por espacios. La herramienta sed (Stream Editor) nos puede ayudar. Aquí está el pipeline general que usaremos:

    I.11_2_UNIX_134_SED_EX1

    Y aquí está parte de la salida, donde solo se representan las secuencias en grupos y cada grupo se representa solo una vez (reemplazando los menos -S con wc contaría así el número de grupos):

    I.11_3_Unix_135_SED_EX1_out

    La herramienta sed es un programa sofisticado para modificar la entrada (ya sea desde un archivo o entrada estándar) e imprimir los resultados a la salida estándar: sed '' <program><file>o... | sed ''<program>.

    Al igual que awk, sed proviene de la década de 1970 y proporciona una gran variedad de potentes características y sintaxis, solo una pequeña fracción de las cuales cubriremos aquí. En particular, nos centraremos en la operación s, o sustitución.

    I.11_4_SED_Sintaxis

    La opción -r que hemos usado le permite saber a sed que queremos que nuestro patrón sea especificado por la sintaxis “expresión regular extendida POSIX”. [1] El patrón general del programa de sustitución es s///g <pattern><replacement>, donde la g especifica que, para cada línea, cada instancia del patrón debe ser reemplazada. Alternativamente, podemos usar 1 en este spot para indicar que solo se debe reemplazar la primera instancia, 2 para indicar solo la segunda, y así sucesivamente. A menudo, <pattern><replacement>se usa s///, ya que tiene el mismo significado que s///1 <pattern><replacement>. [2]

    Expresiones Regulares

    El verdadero poder de sed no proviene de su capacidad de sustituir texto, sino de su utilidad para sustituir texto basado en “patrones” o, más formalmente, expresiones regulares. Una expresión regular es una sintaxis para describir la coincidencia de patrones en cadenas. Las expresiones regulares son descritas por los caracteres individuales que componen el patrón a buscar, y los “meta-operadores” que modifican partes del patrón para mayor flexibilidad. En [ch] at, por ejemplo, los corchetes funcionan como un meta-operador que significa “uno de estos personajes”, y este patrón coincide con gato y sombrero, pero no chat. Las expresiones regulares a menudo se construyen encadenando expresiones más pequeñas, como en [ch] en el [mh] at, gato a juego en el sombrero, gato en el tapete, sombrero en el sombrero y sombrero en el tapete.

    En el ejemplo anterior, todo el patrón fue especificado por _, que no es un meta-operador de ningún tipo, por lo que cada instancia de _ fue reemplazada por el reemplazo (un carácter de espacio). Los meta-operadores que son compatibles con expresiones regulares son muchos y variados, pero aquí hay una lista básica junto con algunos ejemplos biológicamente inspirados:

    • caracteres o cadenas que no son meta-operadores
      • La mayoría de los personajes que no operan de una metamoda son simplemente emparejados. Por ejemplo, _ coincide con _, A coincide con A y ATG coincide con un codón de inicio. (De hecho, ATG son tres patrones individuales especificados en una fila). En caso de duda, suele ser seguro escapar de un personaje (prefijándolo con una diagonal inversa) para asegurarse de que se interprete literalmente. Por ejemplo, \[_\]coincide con la cadena literal [_], en lugar de hacer uso de los corchetes como meta-operadores.
    • .
      • Un periodo coincide con cualquier carácter individual. Por ejemplo, CC. coincide con cualquier codón P (CCA, CCT, CCG, CCC), pero también cadenas como CCX y CC%.
    • [] <charset>
      • Coincide con cualquier carácter individual especificado en<charset>. Por ejemplo, TA [CT] coincide con un codón Y (TAC o TAT).
    • [^] <charset>
      • Colocar un ^ como el primer carácter dentro de los corchetes del juego de caracteres niega el significado, de tal manera que cualquier carácter único que no esté nombrado entre corchetes coincide. TA [^CT] coincide con TAT, TAG, TA%, y así sucesivamente, pero no TAC o TAT.
    • ^ (fuera de [])
      • Colocar un ^ fuera de los corchetes del juego de caracteres coincide con el inicio de la cadena o línea de entrada. Usando sed -r 's/^atg/xxx/G', por ejemplo, reemplaza todas las instancias de codones de inicio por XXX, pero solo si existen al inicio de la línea.
    • $
      • Similar a ^, pero $ coincide con el final de la cadena o línea. Entonces, sed -r 's/ATG$/xxx/G' reemplaza a todos los codones de inicio que existen al final de sus respectivas líneas.

    Hasta ahora nuestros patrones no son realmente tan flexibles, porque la mayoría de las piezas cubiertas hasta este punto coinciden con un solo personaje. Los siguientes cinco metaoperadores resuelven esa limitación.

    • {x, y}
      • Modifica el patrón anterior para que coincida si ocurre entre x e y veces seguidas, inclusive. Por ejemplo, [GC] {4,8} coincide con cualquier cadena de C y/o G que tenga una longitud de cuatro a ocho caracteres (disparando para ocho personajes, si es posible). Entonces, sed -r/[GC] {4,8} /_x_/g' resultaría en las siguientes sustituciones:
        • ATCCGTCT a ATCCGTCT (sin reemplazo)
          ATCCGCGGCTC a AT_X_TC
          ATCGCGGCCCGTTCGGGCCT a AT_X_CCGTT_X_T
      • Usar {0,1} tiene el efecto de hacer que lo que sigue sea opcional en el patrón, y {x,} tiene el efecto de permitir que el patrón coincida x o más veces sin límite superior.
    • *
      • Un asterisco modifica el patrón anterior para que coincida si ocurre cero o más veces; así es equivalente a {0,}.

        El uso de * merece un ejemplo detallado. Considere el patrón ATG [ATGC] *TGA, donde ATG es el patrón para un codón de inicio, [ATGC] * indica cero o más bases de ADN en una fila, y TGA es uno de los codones de parada canónicos. Este patrón coincide con ATGTACCTTGA, y también coincide con ATGTGA (donde la parte media se ha emparejado cero veces).

    • +
      • El modificador de repetición más prominente, un signo más modifica el patrón anterior para que coincida una o más veces; es equivalente a {1,}. En contraste con el ejemplo anterior, ATG [ATGC] +TGA coincide con ATGTACCTTGA y ATGCTGA, pero no ATGTGA.
    • () <pattern>
      • Los paréntesis se pueden utilizar para agrupar una expresión o serie de expresiones en una sola unidad para que puedan operarse juntas. Debido a que AT es el patrón A seguido de T, por ejemplo, AT+ coincide con AT, ATT, ATTT, etc. Si quisiéramos hacer coincidir repeticiones AT, podríamos desear especificar un patrón como (AT) +, que coincida con AT, ATAT, ATAT, y así sucesivamente. Los paréntesis también “guardan” la cadena que coincidió dentro de ellos para su uso posterior. Esto se conoce como retroreferenciación, se discute a continuación.
    • | <pattern x><pattern y>
      • Coincidir con el patrón <pattern x>o el patrón<pattern y>. Se pueden encadenar múltiples patrones u operaciones de este tipo; por ejemplo, TAA|TAG|TGA coincide con cualquiera de los tres codones de parada canónicos. Sin embargo, este ejemplo es un poco ambiguo: ¿este patrón lee “TA (A o T) A (G o T) GA” o “TAA o TAG o TGA”? Para hacerlo concreto, probablemente nos gustaría especificarlo como ((TAA) | (TAG) | (TGA)).

    Usando estas piezas, podemos armar una expresión regular que sirve como un buscador simple (y no realmente útil en la práctica) de lectura abierta. Para las secuencias procariotas (donde los intrones no son una consideración), las definimos como un codón de inicio ATG, seguido de uno o más codones, seguido de uno de los tres codones de parada canónicos TAA, TAG o TGA. El patrón para el inicio es ATG, y hemos visto cómo podemos codificar un stop arriba, con ((TAA) | (TAG) | (TGA)). ¿Qué tal “uno o más codones”? Bueno, “uno o más” se encarna en el operador +, y un codón es cualquiera de tres A, T, C o G. Entonces, “uno o más codones” se codifica como ([ACTG] {3,3}) +. Por lo tanto, la expresión regular de nuestro sencillo buscador de marcos de lectura abierta es:

    I.11_5_Regex_ORF

    En realidad, las expresiones regulares no se utilizan a menudo en la búsqueda de regiones codificantes (aunque a veces se usan para identificar motivos más pequeños). Parte de la razón es que las expresiones regulares son, por defecto, codiciosas: coinciden con el primer patrón que ocurren que pueden, y buscan hacer coincidir tanto de la cadena como puedan. (La maquinaria celular que procesa los marcos de lectura abiertos no es codiciosa de esta manera). Considera la siguiente secuencia, la cual tiene tres marcos de lectura abiertos de acuerdo a nuestra definición simple y expresión regular anterior.

    alt

    Observe que la cadena TAG es tanto un tipo de codón en general ([ACTG] {3,3}) como una parada, por lo que técnicamente ambas de las dos primeras opciones son válidas según la expresión regular. Por las reglas de la codicia, se emparejará el primero, lo que podemos verificar con un simple eco y sed.

    I.11_7_Unix_136_orf_comando_line_ex

    La sintaxis de expresión regular utilizada por sed es similar a la sintaxis utilizada en lenguajes como Perl, Python y R. De hecho, todos los ejemplos que hemos visto hasta ahora funcionarían igual en esos lenguajes (aunque son aplicados por sus propias funciones específicas en lugar de una llamada a sed). Una característica útil proporcionada por los motores de expresión regular más modernos como estos es que los operadores como * y + pueden volverse no codiciosos (aunque prefiero el término más claro “reacio”) siguiéndolos con un signo de interrogación. En Python, la expresión regular ATG ([ACTG] {3,3}) +? ((TAA) | (TAG) | (TGA)) coincidiría con la segunda opción. (Cuando no sigue un *, o +, hace que el anterior sea opcional; así TG (T)? CC es equivalente a TG (T) {0,1} CC.) Las características más sofisticadas permiten al usuario acceder a todas las coincidencias de un patrón, aunque se superpongan, de manera que la más satisfactoria pueda ser sacada por algunos criterios secundarios. Desafortunadamente, sed no admite coincidencias no codiciosas y varias otras características avanzadas de expresión regular.

    Clases de caracteres y expresiones regulares en otras herramientas

    A menudo deseamos usar corchetes para que coincidan con cualquiera de una “clase” de caracteres; por ejemplo, [0123456789] coincide con cualquier dígito individual. La mayoría de las sintaxis de expresión regular (incluida la utilizada por sed) permiten una versión abreviada [0-9] (si quisiéramos hacer coincidir solo un 0, 9 o -, podríamos usar [09-]). Del mismo modo, [a-z] coincide con cualquier letra minúscula y [A-Z] cualquier letra mayúscula. Estos incluso se pueden combinar: [A-za-Z0-9] coincide con cualquier dígito o letra. En la sintaxis extendida POSIX utilizada por sed, 0-9 también se puede especificar como [:digit:]. Observe la falta de corchetes en el anterior, para que realmente coincida con cualquier dígito, la expresión regular es [[:digit:]] (lo cual, sí, es molesto). Para que coincida con cualquier no dígito, podemos negar el conjunto entre corchetes como [^ [:digit:]].

    Estas clases de caracteres POSIX son especialmente útiles cuando queremos hacer coincidir tipos de caracteres que son difíciles de escribir o enumerar. En particular, [[:space:]] coincide con uno de cualquier carácter de espacio en blanco (espacios, tabulaciones, nuevas líneas), y [[:punct:]] coincide con cualquier carácter de “puntuación”, de los cuales hay bastantes. La clase de caracteres [[:space:]] es particularmente útil cuando está reformateando datos almacenados en filas y columnas pero no está seguro de si los separadores de columnas son espacios, tabulaciones o alguna combinación.

    En muchas sintaxis de expresiones regulares (incluidas las utilizadas por Perl, Python, R y algunas versiones de sed), hay disponibles atajos aún más cortos para clases de caracteres. En estos,\ d equivale a [[:digit:]],\ D es equivalente a [^ [:digit:]],\ s para [[:space:]],\ S para [^ [:space:]], entre otros.

    Resulta que las expresiones regulares pueden ser utilizadas tanto por grep como por awk. Al usar grep, podemos especificar que el patrón debe tratarse como una expresión regular extendida agregando la bandera -E (a diferencia de la -r utilizada para sed.) Así grep -E '[[:digit:]] +' extrae líneas que contienen un entero.

    En awk, podemos usar el comparador ~ en lugar del comparador == en una sentencia if, como en awk '{if ($1 ~ /PZ718 [[:digit:]] +/) {print $3}}', que imprime la tercera columna de cada línea donde la primera columna coincide con el patrón PZ718 [[:digit:]] +.

    Back-Referenciación

    De acuerdo con la definición anterior para las líneas de cabecera en el archivo Pz_CDNAS.fasta, los IDs deben caracterizarse como un identificador pseudoaleatoria seguido de, opcionalmente, un guion bajo y un conjunto de letras mayúsculas especificando el grupo. Usando grep '>' para extraer solo las líneas de cabecera, podemos inspeccionar esto visualmente:

    I.11_8_Unix_137_pz_cdna_headers_snippet

    Si enviamos estos resultados a través de wc, vemos que este archivo contiene 471 líneas de cabecera. ¿Cómo podemos verificar que cada uno de ellos siga este patrón? Mediante el uso de una expresión regular con grep para el patrón, y comparando el conteo con 471. Debido a que los ID deben comenzar inmediatamente después del símbolo > en un archivo FASTA, eso será parte de nuestro patrón. Para la sección pseudoaleatoria, que puede o no comenzar con PZ pero al menos no debe incluir un guion bajo o un espacio, podemos usar el patrón [^_ [:space:]] + para especificar uno o más caracteres no subrayados, no espacios en blanco. Para el identificador de grupo opcional, el patrón sería (_ [A-Z] +) {0,1} (porque {0,1} hace que el anterior sea opcional). Armando estos con grep -E y contando los partidos debería producir 471.

    I.11_9_Unix_138_pz_cdna_headers_regex_check

    Todos los encabezados coincidieron con el patrón que esperábamos. ¿Y si no lo hubieran hecho? Podríamos inspeccionar cuáles no usando un grep -v -E para imprimir las líneas que no coincidieron con el patrón.

    Ahora, hipotéticamente, supongamos que un colega (terco, y más senior) ha identificado una lista de identificaciones genéticas importantes, y las ha enviado en un simple archivo de texto.

    I.11_9_Unix_138_2_pz_cdna_headers_needs_fix

    Desafortunadamente, parece que nuestro colega ha decidido utilizar un esquema de nomenclatura ligeramente alterado, añadiendo -gen al final de cada identificador pseudoaleatoria, antes del _, si está presente. Para continuar con colaboraciones pacíficas, podría correspondernos modificar nuestro archivo secuencial para que corresponda a este esquema. Podemos hacer esto con sed, pero será un reto, principalmente porque queremos realizar una inserción, más que una sustitución. En realidad, estaremos realizando una sustitución, ¡pero estaremos sustituyendo partidos con contenidos de ellos mismos!

    En cuanto a las referencias posteriores, en una expresión regular, las coincidencias o subcoincidencias que se agrupan y se encierran entre paréntesis tienen sus cadenas coincidentes guardadas en variables\ 1,\ 2, y así sucesivamente. El contenido del primer par de paréntesis se guarda en\ 1, el segundo en\ 2 (puede ser necesaria cierta experimentación para identificar dónde se guardan las coincidencias entre paréntesis anidados). Toda la coincidencia de expresión se guarda en\ 0.

    Para completar el ejemplo, modificaremos el patrón utilizado en el grep para capturar ambas partes relevantes del patrón, reemplazándolas con\ 1-gen\ 2.

    I.11_10_SED_HEADER_FIX

    Los contenidos de Pz_CDNAS.fasta, luego de ejecutarlo por el sed anterior, son los siguientes:

    I.11_11_Unix_139_pz_cdna_headers_regex_fix

    Las referencias posteriores también se pueden usar dentro del patrón en sí. Por ejemplo, un sed -r/([A-za-Z] +)\ 1/\ 1/g' reemplazaría palabras “duplicadas” ([A-za-Z] +)\ 1 con una sola copia de la palabra\ 1, como en Me gusta mucho sed, resultando en que me gusta mucho sed. Pero ten cuidado si estás pensando en usar la sustitución de este tipo como corrector gramatical, porque esta sintaxis no busca a través de los límites de línea (aunque los programas sed más complejos pueden hacerlo). Este ejemplo no modificaría el siguiente par de líneas (donde la palabra the aparece dos veces):

    The quick sed regex modifies the
    the lazy awk output.

    Algunas notas finales sobre sed y expresiones regulares en general ayudarán a concluir este capítulo.

    1. Las expresiones regulares, aunque poderosas, se prestan a errores. Trabajar de manera incremental y verificar regularmente los resultados.
    2. A menudo es más fácil usar múltiples invocaciones de expresiones regulares (por ejemplo, con múltiples comandos sed) en lugar de intentar crear una sola expresión compleja.
    3. Use expresiones regulares en su caso, pero sepa que no siempre son apropiadas. Muchos problemas que pueden parecer un ajuste natural para las expresiones regulares también se ajustan naturalmente a otras estrategias, que deben tomarse en consideración dada la complejidad que las expresiones regulares pueden agregar a un comando o fragmento de código dado.

    Algunas personas, cuando se enfrentan a un problema, piensan: “Lo sé, usaré expresiones regulares”. Ahora tienen dos problemas.

    ~Jamie Zawinski

    Ejercicios

    1. En el archivo de estadísticas de ensamblaje de novo contig_stats.txt, los ID de cóntigo se denominan NODE_1, NODE_2, etc. Preferiríamos que se llamaran contig1, contig2 y similares. Producir un contig_stats_renamed.txt con estos cambios realizados.
    2. ¿Cuántas secuencias en el archivo Pz_CDNAS.fasta están compuestas por una sola lectura? Es probable que necesite usar tanto awk como sed aquí, y asegúrese de verificar cuidadosamente los resultados de su tubería con menos.
    3. Un colega particularmente odioso insiste en que en el archivo Pz_CDNAS.fasta, las secuencias que no forman parte de ningún grupo (es decir, las que no tienen _ sufijo) deben tener el sufijo _nogroup. Apaciguar a este colega produciendo un archivo a esta especificación llamado Pz_CDNAS_FIXED.FASTA.
    4. Las líneas cabeceras en el conjunto de proteínas de levadura orf_trans.fasta se ven así cuando se ven con menos -S después de grepping para >:I.11_12_Unix_139_2_ORF_Trans_Headers Notablemente, las líneas de encabezado contienen información sobre las ubicaciones de los exones individuales; la secuencia YAL001C tiene dos exones en cromosoma I de las ubicaciones 151006 a 147594 y 151166 a 151097 (los números van de grandes a pequeños porque las ubicaciones se especifican en la cadena directa, pero el gen está en la cadena inversa del complemento). Por el contrario, la secuencia YAL002W tiene solo un exón en la cadena directa.

      ¿Cuántas secuencias están compuestas por un solo exón? A continuación, produzca una lista de ID de secuencia en un archivo llamado multi_exon_ids.txt que contenga todos esos ID de secuencia con más de un exón como una sola columna.

    5. Como continuación de la pregunta 4, ¿qué secuencia tiene más exones? ¿Qué secuencia de un solo exón es la más larga, en términos de la distancia desde la primera posición hasta la última posición señalada en la lista de exones?

    1. POSIX, abreviatura de Interfaz de sistema operativo portátil, define un conjunto básico de estándares para programas y sistemas operativos para que diferentes sistemas operativos similares a UNIX puedan interoperar.
    2. También debemos tener en cuenta que los/delimitadores son los más utilizados, pero la mayoría de los caracteres se pueden usar en su lugar; por ejemplo, s| | |g <pattern><replacement>puede facilitar el reemplazo de/caracteres.

    This page titled 1.11: Patrones (Expresiones Regulares) is shared under a CC BY-NC-SA license and was authored, remixed, and/or curated by Shawn T. O’Neil (OSU Press) .