{ "cells": [ { "attachments": { "imagen.png": { "image/png": "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" } }, "cell_type": "markdown", "metadata": {}, "source": [ "![imagen.png](attachment:imagen.png)\n", "

Introduccion a Regex

\n", "Basado en el tutorial de W3schools: link y en el sitio oficial de python RE: link\n", "

Una expresión regular (o RE, por sus siglas en inglés) especifica un conjunto de cadenas que coinciden con ella; las funciones de este módulo permiten comprobar si una determinada cadena coincide con una expresión regular dada (o si una expresión regular dada coincide con una determinada cadena, que se reduce a lo mismo).

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

1. Presentacion

\n", "Python tiene un paquete integrado llamado re, que se puede usar para trabajar con expresiones regulares." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# Importacion de librerias\n", "import re" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Manejo de expresiones regulares con RE\n", "SI! Verificado! La cadena empieza con 'No' y termina con 'Aires'\n" ] } ], "source": [ "# Verifica si una cadena empieza con \"No\" y termina con \"Aires\":\n", "# En re.search, cambie \"txt\" por \"txt2\" y observe los efectos:\n", "\n", "print(\"Manejo de expresiones regulares con RE\")\n", "txt = \"No llueve en Buenos Aires\"\n", "txt2=\"Pasamos 3 meses con temperaturas entre 28 y 38 grados\"\n", "x = re.search(\"^No.*Aires$\", txt)\n", "\n", "if x:\n", " print(\"SI! Verificado! La cadena empieza con 'No' y termina con 'Aires'\")\n", "else:\n", " print(\"NO: no se halló en la cadena lo buscado\")\n", "# El demo original se hizo en Marzo de 2023, en medio de las históricas olas de calor. De ahí, los comentarios presentados." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Funciones Regex\n", "El módulo RE ofrece un conjunto de funciones que nos permite buscar una sub-cadena dentro una cadena:\n", "* findall: Devuelve una lista que contiene todas las coincidencias\n", "* search: Devuelve un objeto Match si hay una coincidencia en cualquier parte de la cadena\n", "* split: Devuelve una lista donde la cadena se ha dividido en cada coincidencia\n", "* sub: Reemplaza una o varias coincidencias con una cadena" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.1. Meta-caracteres\n", "Los Meta caracteres son caracteres con significado especial:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "

1. [] Un conjunto de caracteres. Por ejemplo: \"[a-m]\"\t
\n", "2. \\ Señala una secuencia especial (se puede usar para escapar de caracteres especiales). Por ejemplo: \"\\d\"\t
\n", "3. . Cualquier caracter (excepto caracter de Nueva Linea). Por ejemplo:\t\"he..o\"\t
\n", "4. ^ Empieza con. Por ejemplo:\t\"^hello\"
\n", "5. $ Termina con. Por ejemplo:\t'\"planet$\"\t
\n", "6. * Ninguna o mas ocurrencias. 'Por ejemplo: \"he.*o\"
\t\n", "7. + Una o más ocurrencias. Por 'ejemplo: \"he.+o\"\t
\n", "8. ? Ninguna o una ocurrencia. Por ejemplo: \"he.?o\"\t
\n", "9. {} Exactamente el numero específico de ocurrencias. Por ejemplo: \"he.{2}o\"
\t\n", "10. | Cualquiera o. Por ejemplo: \"falls|stays\"\t
\n", "11. () Capturar y agrupar

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.1. [] Un conjunto de caracteres" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['l', 'l', 'e', 'e', 'e', 'e', 'i', 'e']\n" ] } ], "source": [ "#Busca todas las letras minusculas entre \"a\" y \"m\":\n", "\n", "x = re.findall(\"[a-m]\", txt)\n", "print('Cadena: ',txt)\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.2. \\ Señala una secuencia especial (se puede usar para escapar de caracteres especiales)." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['3', '2', '8', '3', '8']\n" ] } ], "source": [ "# Encuentra todos los caracteres de dígitos:\n", "\n", "x = re.findall(\"\\d\", txt2)\n", "print('Cadena: ',txt2)\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.3. . Cualquier caracter (excepto caracter de Nueva Linea)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['llueve']\n" ] } ], "source": [ "# Busca una secuencia que inicia con \"ll\", seguido por tres caracteres cualesquiera, y luego una \"e\":\n", "\n", "x = re.findall(\"ll...e\", txt)\n", "print('Cadena: ',txt)\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.4. ^ Empieza con" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['No']\n", "Si, el string empieza con 'No'\n" ] } ], "source": [ "# Verifica si el string empieza con 'No':\n", "\n", "x = re.findall(\"^No\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "if x:\n", " print(\"Si, el string empieza con 'No'\")\n", "else:\n", " print(\"No, el string no empieza con 'No'\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.5. $ Termina con" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "Si, el string termina con 'Aires'\n" ] } ], "source": [ "# Verifica si el string termina con 'aires':\n", "\n", "x = re.findall(\"Aires$\", txt)\n", "print('Cadena: ',txt)\n", "if x:\n", " print(\"Si, el string termina con 'Aires'\")\n", "else:\n", " print(\"No, el string termina con 'Aires'\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.6. * Ninguna o mas ocurrencias" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['con temperaturas entre 28 y 38 grados']\n" ] } ], "source": [ "# Busca una secuencia que empieza \"con\", seguida por 0 más caracteres (cualquiera), y una \"s\":\n", "\n", "x = re.findall(\"con.*s\", txt2)\n", "print('Cadena: ',txt2)\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.7. + Una o más ocurrencias" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['con temperaturas entre 28 y 38 grados']\n" ] } ], "source": [ "# Busca una secuencia que empieza \"con\", seguida por 1 o más caracteres (cualquiera), y una \"s\":\n", "\n", "x = re.findall(\"con.+s\", txt2)\n", "print('Cadena: ',txt2)\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.8. ? Ninguna o una ocurrencia" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "[]\n" ] } ], "source": [ "# Busca una secuencia que empiece con \"con\", seguido por 0 o 1 caracter (cualquiera), luego y una \"s\":\n", "\n", "x = re.findall(\"con.?s\", txt2)\n", "print('Cadena: ',txt2)\n", "print(x)\n", "# Esta vez no halla la secuencia, por lo que imprime una lista vacia." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.9. {} Exactamente el numero específico de ocurrencias" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "[]\n" ] } ], "source": [ "# Busca una secuencia que empiece con \"con\" seguida de exactamente 2 caracteres (cualquiera), y luego una \"s\":\n", "\n", "x = re.findall(\"con.{2}s\", txt2)\n", "print('Cadena: ',txt2)\n", "print(x)\n", "# Esta vez no halla la secuencia, por lo que imprime una lista vacia. \n", "# Por ejemplo, si cambiamos la \"s\" por una \"e\" habria resultado: print(re.findall(\"con.{2}e\", txt2))=['con te']" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.10. | Cualquiera o" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['Aires']\n", "Si, hay al menos una coincidencia!\n" ] } ], "source": [ "# Verifica si el string contiene \"falls\" or \"Aires\":\n", "\n", "x = re.findall(\"falls|Aires\", txt)\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"Si, hay al menos una coincidencia!\")\n", "else:\n", " print(\"No hay coincidencia\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.1.11. () Capturar y agrupar" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.2. Secuencias especiales\n", "Una secuencia especial es una \\ seguida de uno o más caracteres específicos y tienen un significado específico.\n", "1. \\A: Devuelve una coincidencia si los caracteres especificados están al principio de la cadena. Por ejemplo: \"\\AThe\"\n", "2. \\b: Devuelve una coincidencia donde los caracteres especificados están al principio o al final de una palabra (la \"r\" al principio se asegura de que la cadena se trate como una \"cadena sin procesar\"). Por ejemplo:\tr\"\\bain\"\n", "r\"ain\\b\"\n", "3. \\B: Devuelve una coincidencia donde los caracteres especificados están presentes, pero NO al principio (o al final) de una palabra (la \"r\" al principio se asegura de que la cadena se trate como una \"cadena sin procesar\"). Por ejemplo: r\"\\Bain\" r\"ain\\B\"\n", "4. \\d: Devuelve una coincidencia donde la cadena contiene dígitos (números del 0 al 9). Por ejemplo: r\"\\d\"\n", "5. \\D: Devuelve una coincidencia donde la cadena NO contiene dígitos (números del 0 al 9). Por ejemplo: \"\\D\"\n", "6. \\s: Devuelve una coincidencia donde la cadena contiene un carácter de espacio en blanco. Por ejemplo: \"\\s\"\n", "7. \\S: Devuelve una coincidencia donde la cadena NO contiene ningun espacio en blanco. Por ejemplo: \"\\S\"\n", "8. \\w: Devuelve una coincidencia en la que la cadena contiene cualquier caracter alfnumerico (caracteres de la A a la Z, dígitos del 0 al 9 y el carácter de subrayado _). Por ejemplo: \"\\w\"\n", "9. \\W: Devuelve una coincidencia en la que la cadena NO contiene ningun caracter alfanumerico. Por ejemplo: \"\\W\"\n", "10. \\Z: Devuelve una coincidencia si los caracteres especificados están al final de la cadena. Por ejemplo: \"\\Zres\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.1. \\A: Devuelve una coincidencia si los caracteres especificados están al principio de la cadena." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['No']\n", "SI, la cadena empieza con 'No'\n" ] } ], "source": [ "# Verifica si la cadena inicia con \"No\":\n", "\n", "x = re.findall(\"\\ANo\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, la cadena empieza con 'No'\")\n", "else:\n", " print(\"No hay coincidencia\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.2. \\b: Devuelve una coincidencia donde los caracteres especificados están al principio o al final de una palabra (la \"r\" al principio se asegura de que la cadena se trate como una \"cadena sin procesar\")." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['me']\n", "SI, hay al menos una coincidencia de una palabra que inicia con 'me'\n" ] } ], "source": [ "# Verifica si \"me\" está al inicio de una palabra:\n", "\n", "x = re.findall(r\"\\bme\", txt2)\n", "\n", "print('Cadena: ',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos una coincidencia de una palabra que inicia con 'me'\")\n", "else:\n", " print(\"NO. Ninguna palabra empieza con 'me'\")" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "[]\n", "NO. Ninguna palabra finaliza con 'me'\n" ] } ], "source": [ "# Verifica si \"me\" está al final de una palabra:\n", "\n", "x = re.findall(r\"me\\b\", txt2)\n", "\n", "print('Cadena: ',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos una coincidencia de una palabra que finaliza con 'me'\")\n", "else:\n", " print(\"NO. Ninguna palabra finaliza con 'me'\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.3. \\B: Devuelve una coincidencia donde los caracteres especificados están presentes, pero NO al principio (o al final) de una palabra (la \"r\" al principio se asegura de que la cadena se trate como una \"cadena sin procesar\")." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "[]\n", "NO, hay coincidencia\n" ] } ], "source": [ "# Verifica si \"me\" esta presente, pero NO al inicio de ninguna palabra:\n", "\n", "x = re.findall(r\"\\Bme\", txt2)\n", "\n", "print('Cadena: ',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, 'me' esta presente pero no al inicio de ninguna palabra\")\n", "else:\n", " print(\"NO, hay coincidencia\")" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['me']\n", "SI, 'me' esta presente pero no al inicio de ninguna palabra\n" ] } ], "source": [ "# Verifica si \"me\" esta presente, pero NO al final de alguna palabra:\n", "\n", "x = re.findall(r\"me\\B\", txt2)\n", "\n", "print('Cadena: ',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, 'me' esta presente pero no al inicio de ninguna palabra\")\n", "else:\n", " print(\"NO, hay coincidencia\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.4. \\d: Devuelve una coincidencia donde la cadena contiene dígitos (números del 0 al 9)." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['3', '2', '8', '3', '8']\n", "SI, hay al menos un digito!\n" ] } ], "source": [ "# Verifica si la cadena contiene algun digito decimal (numeros de 0-9):\n", "\n", "x = re.findall(\"\\d\", txt2)\n", "\n", "print('Cadena: ',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un digito!\")\n", "else:\n", " print(\"NO, no hay ningun digito decimal\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.5. \\D: Devuelve una coincidencia donde la cadena NO contiene dígitos (números del 0 al 9)." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['N', 'o', ' ', 'l', 'l', 'u', 'e', 'v', 'e', ' ', 'e', 'n', ' ', 'B', 'u', 'e', 'n', 'o', 's', ' ', 'A', 'i', 'r', 'e', 's']\n", "SI, hay al menos un caracter no decimal!\n" ] } ], "source": [ "# Verifica si la cadena contiene algun digito NO decimal (NO numeros de 0-9):\n", "\n", "x = re.findall(\"\\D\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un caracter no decimal!\")\n", "else:\n", " print(\"NO, no hay ningun caracter no decimal\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.6. \\s: Devuelve una coincidencia donde la cadena contiene un carácter de espacio en blanco." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "[' ', ' ', ' ', ' ']\n", "SI, hay al menos un espacio en blanco!\n" ] } ], "source": [ "# Devuelve una coincidencia por cada espacio en blanco\n", "\n", "x = re.findall(\"\\s\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un espacio en blanco!\")\n", "else:\n", " print(\"NO, no hay ningun espacio en blanco\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.7. \\S: Devuelve una coincidencia donde la cadena NO contiene ningun espacio en blanco." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['N', 'o', 'l', 'l', 'u', 'e', 'v', 'e', 'e', 'n', 'B', 'u', 'e', 'n', 'o', 's', 'A', 'i', 'r', 'e', 's']\n", "SI, hay al menos un caracter distinto al espacio en blanco\n" ] } ], "source": [ "# Devuelve una coincidencia por cada caracter NO espacio en blanco\n", "\n", "x = re.findall(\"\\S\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un caracter distinto al espacio en blanco\")\n", "else:\n", " print(\"No, solo hay espacios en blanco\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.8. \\w: Devuelve una coincidencia en la que la cadena contiene cualquier caracter alfnumerico (caracteres de la A a la Z, dígitos del 0 al 9 y el carácter de subrayado _)." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['N', 'o', 'l', 'l', 'u', 'e', 'v', 'e', 'e', 'n', 'B', 'u', 'e', 'n', 'o', 's', 'A', 'i', 'r', 'e', 's']\n", "SI, hay al menos un caracter alfanumerico\n" ] } ], "source": [ "# Devuelve una coincidencia por cada caracter alfanumérico que tenga la cadena (caracteres de a a la Z, digitos de 0-9, caracter _ ):\n", "\n", "x = re.findall(\"\\w\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un caracter alfanumerico\")\n", "else:\n", " print(\"NO, no hay ningun caracter alfanumerico\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.9. \\W: Devuelve una coincidencia en la que la cadena NO contiene ningun caracter alfnumerico." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "[' ', ' ', ' ', ' ']\n", "SI, hay al menos un caracter NO alfanumerico\n" ] } ], "source": [ "# Devuelve una coincidencia por cada caracter NO alfanumerico.\n", "\n", "x = re.findall(\"\\W\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un caracter NO alfanumerico\")\n", "else:\n", " print(\"NO, todos los caracteres son alfanumericos\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.2.10. \\Z: Devuelve una coincidencia si los caracteres especificados están al final de la cadena." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['res']\n", "SI, la cadena termina con 'res'\n" ] } ], "source": [ "# Verifica si la cadena termina con \"res\"\n", "\n", "x = re.findall(\"res\\Z\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, la cadena termina con 'res'\")\n", "else:\n", " print(\"NO, la cadena no termina con 'res\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.3. Conjuntos\n", "Un conjunto es un conjunto de caracteres dentro de un par de corchetes [] con un significado especial:\n", "

1. [arn] Devuelve una coincidencia en la que está presente uno de los caracteres especificados (a, r o n)\t
\n", "2. [a-n] Devuelve una coincidencia para cualquier carácter en minúscula, alfabéticamente entre a y n\t
\n", "3. [^arn] Devuelve una coincidencia para cualquier carácter EXCEPTO a, r y n\t
\n", "4. [0123] Devuelve una coincidencia en la que cualquiera de los dígitos especificados (0, 1, 2 o 3) está presente
\t\n", "5. [0-9] Devuelve una coincidencia para cualquier dígito entre 0 y 9\t
\n", "6. [0-5][0-9] Devuelve una coincidencia para cualquier número de dos dígitos entre 00 y 59
\t\n", "7. [a-zA-Z] Devuelve una coincidencia para cualquier carácter alfabéticamente entre a y z, minúsculas O mayúsculas
\t\n", "8. [+] En conjuntos, +, *, ., |, (), $,{} no tiene un significado especial, por lo que [+] significa: devolver una coincidencia para cualquier carácter + en la cadena

" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.1. [arn] Devuelve una coincidencia en la que está presente uno de los caracteres especificados (a, r o n)" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena: No llueve en Buenos Aires\n", "['n', 'n', 'r']\n", "SI, la cadena presenta alguno de los caracteres del conjunto\n" ] } ], "source": [ "# Verifica si la cadena tiene alguna a, r o n\n", "\n", "x = re.findall(\"[arn]\", txt)\n", "\n", "print('Cadena: ',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, la cadena presenta alguno de los caracteres del conjunto\")\n", "else:\n", " print(\"NO, la cadena no tiene ninguno de los caracteres del conjunto\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.2. [a-n] Devuelve una coincidencia para cualquier carácter en minúscula, alfabéticamente entre a y n" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= No llueve en Buenos Aires\n", "['l', 'l', 'e', 'e', 'e', 'n', 'e', 'n', 'i', 'e']\n", "SI, hay al menos un caracter el la cadena entre a y n\n" ] } ], "source": [ "# Verifica si la cadena tiene algun caracter entre a y n:\n", "\n", "x = re.findall(\"[a-n]\", txt)\n", "\n", "print('Cadena=',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un caracter el la cadena entre a y n\")\n", "else:\n", " print(\"NO, no hay ningun caracter en la cadena entre a y n\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.3. [^arn] Devuelve una coincidencia para cualquier carácter EXCEPTO a, r y n" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= No llueve en Buenos Aires\n", "['N', 'o', ' ', 'l', 'l', 'u', 'e', 'v', 'e', ' ', 'e', ' ', 'B', 'u', 'e', 'o', 's', ' ', 'A', 'i', 'e', 's']\n", "SI, la cadena tiene otros caracteres distinos a los del conjunto\n" ] } ], "source": [ "# Verifica si la cadena tiene otros caracteres diferentes a a, r, or n:\n", "\n", "print('Cadena=',txt)\n", "x = re.findall(\"[^arn]\", txt)\n", "\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, la cadena tiene otros caracteres distinos a los del conjunto\")\n", "else:\n", " print(\"NO, la cadena solo tiene los caracteres del conjunto\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.4. [0123] Devuelve una coincidencia en la que cualquiera de los dígitos especificados (0, 1, 2 o 3) está presente" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['3', '2', '3']\n", "SI, hay al menos un dígito del conjunto en la cadena\n" ] } ], "source": [ "# Verifica si la cadena tiene alguno de los dígitos dentro del conjunto 0, 1, 2, o 3\n", "\n", "x = re.findall(\"[0123]\", txt2)\n", "print('Cadena=',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un dígito del conjunto en la cadena\")\n", "else:\n", " print(\"NO, no hay ningún dígito del conjunto en la cadena\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.5. [0-9] Devuelve una coincidencia para cualquier dígito entre 0 y 9" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['3', '2', '8', '3', '8']\n", "SI, hay al menos un dígito del conjunto en la cadena\n" ] } ], "source": [ "# Verifica si la cadena tiene alguno de los dígitos del conjunto\n", "\n", "x = re.findall(\"[0-9]\", txt2)\n", "print('Cadena=',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un dígito del conjunto en la cadena\")\n", "else:\n", " print(\"NO, no hay ningún dígito del conjunto en la cadena\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.6. [0-5][0-9] Devuelve una coincidencia para cualquier número de dos dígitos entre 00 y 59" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "['28', '38']\n", "SI, hay al menos un par de dígitos en la cadena entre 00 y 59\n" ] } ], "source": [ "# Verifica si la cadena tiene algun par de digitos entre 00 y 59\n", "\n", "x = re.findall(\"[0-5][0-9]\", txt2)\n", "print('Cadena=',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, hay al menos un par de dígitos en la cadena entre 00 y 59\")\n", "else:\n", " print(\"NO, en la cadena no hay ningun par de dígitos 00 y 59\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.7. [a-zA-Z] Devuelve una coincidencia para cualquier carácter alfabéticamente entre a y z, minúsculas O mayúsculas" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= No llueve en Buenos Aires\n", "['N', 'o', 'l', 'l', 'u', 'e', 'v', 'e', 'e', 'n', 'B', 'u', 'e', 'n', 'o', 's', 'A', 'i', 'r', 'e', 's']\n", "SI, la cadena tiene al menos una minúscula y una mayúscula\n" ] } ], "source": [ "#Verifica si la cadena tiene al menos una letra mayúscula Y una letra minúscula:\n", "\n", "x = re.findall(\"[a-zA-Z]\", txt)\n", "print('Cadena=',txt)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, la cadena tiene al menos una minúscula y una mayúscula\")\n", "else:\n", " print(\"NO, la cadena no tiene al menos una mayúscula y una minúscula\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.3.8. [+] En conjuntos, +, *, ., |, (), $,{} no tiene un significado especial, por lo que [+] significa: devolver una coincidencia para cualquier carácter + en la cadena" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "[]\n", "NO, la cadena no tiene un caracter '+'\n" ] } ], "source": [ "# Verifica si la cadena tiene un caracter +\n", "\n", "x = re.findall(\"[+]\", txt2)\n", "print('Cadena=',txt2)\n", "print(x)\n", "\n", "if x:\n", " print(\"SI, la cadena tiene al menos un caracter '+'\")\n", "else:\n", " print(\"NO, la cadena no tiene un caracter '+'\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.4. La funcion 'findall()'\n", "Devuelve una lista conteniendo todas las coincidencias." ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "Sub-Cadena= do\n", "['do']\n" ] } ], "source": [ "# Devuelve una lista conteniendo ocurrencias de una subcadena\n", "print('Cadena=',txt2)\n", "sub1='do'\n", "print('Sub-Cadena=',sub1)\n", "x = re.findall(sub1, txt2)\n", "print(x)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.5. La funcion 'search()'\n", "Esta función busca una coincidencia en la cadena y devuelve un objeto Match si hay una coincidencia.\n", "\n", "Si hay más de una coincidencia, solo se devolverá la primera aparición de la coincidencia:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados - subcadena= tu\n", "La posicion de la primer aparicion de tu es: 27\n" ] } ], "source": [ "# Buscaremos la posición de la primer aparición de la subcadena \"tu\"\n", "\"\"\"\n", "sub2='tu'\n", "x = re.search(sub2, txt2)\n", "print('Cadena=',txt2)\n", "pos=x.start()\n", "print(\"La posicion de la primer aparicion de \",sub2,\" es:\", pos)\n", "\"\"\"\n", "# PRECAUCION: Si la subcadena sub2 no está en la cadena txt2, arroja ERROR!\n", "# \n", "# Sugerencia: primero ver si está. Y si está, buscar la posicion. \n", "# -----------\n", "sub2='tu'\n", "print('Cadena=',txt2,' - subcadena=',sub2)\n", "x=re.findall(sub2,txt2)\n", "if(len(x)>0):\n", " x = re.search(sub2, txt2)\n", " pos=x.start()\n", " print(\"La posicion de la primer aparicion de\",sub2,\" es:\", pos)\n", "else:\n", " print(\"La subcadena '\",sub2,\"' no se hallo en la cadena '\", txt2,\"´\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### 2.5.1. El objeto search()\n", "El objeto search() tiene métodos y propiedades usadas para recuperar información relacionada con la búsqueda:\n", "1. span(): devuelve una tupla que contiene las posiciones inicio y fin de la busqueda.\n", "2. string: devuelve la cadena pasada a la función.\n", "3. group(): devuelve la parte de la cadena donde hubo una coincidencia." ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados - subcadena= tu\n", "span(): (27, 29)\n", "string: Pasamos 3 meses con temperaturas entre 28 y 38 grados\n", "group(): tu\n" ] } ], "source": [ "# Métodos del objeto Search:\n", "\n", "print('Cadena=',txt2,' - subcadena=',sub2)\n", "x = re.search(sub2, txt2)\n", "\n", "# span(): Las posiciones de inicio y fin de la coincidencia\n", "print('span():',x.span())\n", "# string: La cadena pasada a la función.\n", "print('string:',x.string)\n", "# group(): La parte donde hubo coincidencia\n", "print('group():',x.group())\n", "\n", "# IMPORTANTE: \n", "# Vale la aclaración anterior: si el objeto es vacio, da ERROR." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.6. La funcion 'split()'\n", "La funcion 'split()' separa a la cadena segun una subcadena" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados subcadena= as\n", "['P', 'amos 3 meses con temperatur', ' entre 28 y 38 grados']\n" ] } ], "source": [ "# Devuelve una lista resultado de la separacion de la cadena por la subcadena\n", "sub='as'\n", "print('Cadena=',txt2,' subcadena=',sub)\n", "x = re.split(sub, txt2)\n", "print(x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 2.7. La funcion 'sub()'\n", "La funcion sub() reemplaza las coincidencias con el texto de su elección." ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cadena= Pasamos 3 meses con temperaturas entre 28 y 38 grados subcadena= as reemplazo= XX\n", "PXXamos 3 meses con temperaturXX entre 28 y 38 grados\n" ] } ], "source": [ "# Reemplaza sub=\"as\" por nuevaSub=\"XX\" en la cadena.\n", "nuevaSub=\"XX\"\n", "print('Cadena=',txt2,' subcadena=',sub,'reemplazo=',nuevaSub)\n", "x = re.sub(sub, nuevaSub, txt2)\n", "print(x)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "base", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.10" } }, "nbformat": 4, "nbformat_minor": 2 }