{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Ayudantía 7: I/O 🖥️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Ayudantes  👾\n",
    "- [Clemente Campos](https://github.com/mskdancers)\n",
    "- [Patricio Hinostroza](https://github.com/Dvckhv)\n",
    "- [Julio Huerta](https://github.com/julius)\n",
    "- [Carlos Olguin](https://github.com/CarlangaUC)\n",
    "- [Catalina Miranda](https://github.com/catalinamirandah)\n",
    "- [Felipe Vidal](https://github.com/fvidalf)\n",
    "\n",
    "## 📖 Contenidos 📖\n",
    "\n",
    "En esta ayudantía usaremos:\n",
    "\n",
    "- I/O\n",
    "- Strings\n",
    "- RegEx\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# I/O"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ya hemos visto cómo podíamos manejar archivos en el curso:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hola, quiero entrar al archivo :D\n"
     ]
    }
   ],
   "source": [
    "contenido = \"Hola, quiero entrar al archivo :D\"\n",
    "\n",
    "# Guardamos el contenido en un archivo con encoding UTF-8\n",
    "file = open(\"data/archivo\", \"w\", encoding='utf-8', errors=\"replace\")\n",
    "file.write(contenido)\n",
    "\n",
    "# Pero leemos el mismo archivo con encoding ASCII\n",
    "file = open('data/archivo', \"r\", encoding='ascii', errors='replace')\n",
    "print(file.read())\n",
    "file.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Pero a veces, cuando tenemos que interactuar con algunos módulos de software que sólo leen y escriben sus datos desde y hacia archivos, puede resultar conveniente emular el tener un archivo usando los módulos de Python `StringIO` o `BytesIO`.\n",
    "\n",
    "`StringIO` y `BytesIO` son utilizados para tratar cadenas de caracteres y bytes como si fueran objetos tipo archivo en memoria."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "b'Soy un byte :D \\x00\\x01 archivado'\n"
     ]
    }
   ],
   "source": [
    "import io\n",
    "\n",
    "data = io.BytesIO(b\"Soy un byte :D \\x00\\x01 \")\n",
    "print(data.getvalue() + b'archivado')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Soy un string ahora :D\n",
      "\n"
     ]
    }
   ],
   "source": [
    "data = io.StringIO()\n",
    "data.write('Soy un string ahora ')\n",
    "\n",
    "print(':D', file=data)\n",
    "\n",
    "print(data.getvalue())\n",
    "\n",
    "data.close()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Strings\n",
    "\n",
    "Hasta el momento hemos trabajado con strings como si fueran una estructura de datos del montón, que solamente utilizamos en el contexto de un print o de un input. Sin embargo podemos sacarles más provecho en tareas de visualización.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejemplo 1: lectura de archivos\n",
    "\n",
    "Lea el archivo `text_ex.txt` en formato `utf-8` y luego en `ascii` ignorando los caracteres que no se puedan codificar. Luego pruebe reemplazando los caracteres inválidos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tamaño 6896\n",
      "tamaño 3276\n"
     ]
    }
   ],
   "source": [
    "with open('data/text_ex.txt', \"r\" ,'completar') as f:\n",
    "    data = f.readlines()\n",
    "\n",
    "print(f\"tamaño {len( ''.join(data))}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Infinidad de métodos de Strings"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isascii', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'removeprefix', 'removesuffix', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']\n"
     ]
    }
   ],
   "source": [
    "print(dir(str))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Format strings e impresión"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Podemos utilizar los siguientes añadidos para darle formato a nuestros strings:\n",
    "```\n",
    "format_spec     ::=  [[fill]align][sign][\"z\"][\"#\"][\"0\"][width][grouping_option][\".\" precision][type]\n",
    "fill            ::=  <any character>\n",
    "align           ::=  \"<\" | \">\" | \"=\" | \"^\"\n",
    "sign            ::=  \"+\" | \"-\" | \" \"\n",
    "width           ::=  digit+\n",
    "grouping_option ::=  \"_\" | \",\"\n",
    "precision       ::=  digit+\n",
    "type            ::=  \"b\" | \"c\" | \"d\" | \"e\" | \"E\" | \"f\" | \"F\" | \"g\" | \"G\" | \"n\" | \"o\" | \"s\" | \"x\" | \"X\" | \"%\"\n",
    "```\n",
    "\n",
    "Donde, personalmente nos interesa:\n",
    "- allign: alineación del string\n",
    "- width: largo del string\n",
    "- precisión: cantidad de decimales\n",
    "- type: tipo de dato\n",
    "- fill: carácter de relleno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ejemplo\n",
    "\n",
    "Dentro de la carpeta `data`, existe un archivo llamado `personajes.csv`, el cual tiene como primera línea lo siguiente:\n",
    "\n",
    "`Nombre, Vida, Ataque, Poder`\n",
    "\n",
    "y luego, cada línea tiene los datos de un personaje, donde:\n",
    "- Nombre: Nombre del personaje (string)\n",
    "- Vida: Vida del personaje (entero)\n",
    "- Ataque: Ataque del personaje (float, max 1 decimal)\n",
    "- Poder: Nombre del poder del personaje (string, maximo 15 caracteres).\n",
    "\n",
    "Imprima en una tabla los datos de los personajes con las restricciones mencionadas, logre que cada columna se separe con un `|`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# RegEx"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las expresiones regulares (o RegEx por su sigla en inglés) nos ayudan a encontrar patrones dentro de strings para así poder filtrar los que necesitemos."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Utilizan algunos caracteres especiales, denominados meta-caracteres para especificar patrones más generales. Los meta-caracteres son los siguientes:\n",
    "\n",
    "- `[ ]`: Define clases de caracteres, como `[abc]` para hacer match con a, b o c. Puedes utilizar `-` para rangos, y `[^abc]` para negación (match con cualquier carácter excepto a, b y c).\n",
    "\n",
    "- `+`: Indica que la expresión regular se puede repetir una o más veces.\n",
    "\n",
    "- `*`: Indica que la expresión regular se puede repetir cero o más veces.\n",
    "\n",
    "- `?`: Indica que la expresión regular puede estar presente una vez o no estar.\n",
    "\n",
    "- `{m, n}`: Permite repetir la expresión regular entre m y n veces (inclusive). Puede ser {m} para una cantidad fija.\n",
    "\n",
    "- `.`: Hace match con cualquier carácter, excepto un salto de línea.\n",
    "\n",
    "- `^`: Especifica el inicio del string.\n",
    "\n",
    "- `$`: Especifica el final del string.\n",
    "\n",
    "- `( )`: Delimita y crea grupos en la expresión regular.\n",
    "\n",
    "- `A | B`: Permite hacer match con A o B.\n",
    "\n",
    "- `\\`: Escapa los meta-caracteres para que se traten como caracteres normales en el patrón."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python provee el módulo re para el uso de expresiones regulares. Dentro de las funciones disponibles en el módulo re de Python se encuentran:\n",
    "\n",
    "- `re.match()` verifica si un substring cumple con la expresión regular a partir del inicio del string.\n",
    "- `re.fullmatch()` verifica si el string completo cumple con la expresión regular\n",
    "- `re.search()` verifica si algún substring cumple con la expresión regular.\n",
    "- `re.sub()` permite reemplazar un patrón por otra secuencia de caracteres en un string.\n",
    "- `re.split()` permite separar un string de acuerdo a un patrón."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Validación de Contraseñas🔐\n",
    "\n",
    "Tu tarea es escribir un programa en Python que valide si las contraseñas cumplen con ciertos requisitos. Debes usar expresiones regulares y las funciones del módulo re para realizar esta validación. Las reglas para las contraseñas son las siguientes:\n",
    "\n",
    "- La contraseña debe tener al menos 8 caracteres de longitud.\n",
    "- Debe contener al menos una letra mayúscula.\n",
    "- Debe contener al menos una letra minúscula.\n",
    "- Debe contener al menos un número.\n",
    "- Puede contener caracteres especiales, como !, @, #, $, %.\n",
    "\n",
    "La función `validar_contrasena(contrasena)` retornará `True` en caso de que sea válida la contraseña o `False` en caso contrario."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "def validar_contrasena(contrasena):\n",
    "    pass\n",
    "\n",
    "# Lista de contraseñas para validar\n",
    "contrasenas = [\n",
    "    \"P@ssw0rd\",\n",
    "    \"Segura123\",\n",
    "    \"Micontra123\",\n",
    "    \"Abc123!\",\n",
    "    \"demasiadoCorta\",\n",
    "]\n",
    "\n",
    "for contrasena in contrasenas:\n",
    "    if validar_contrasena(contrasena):\n",
    "        print(f\"'{contrasena}' es una contraseña válida.\")\n",
    "    else:\n",
    "        print(f\"'{contrasena}' no es una contraseña válida.\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Validación de Números de Teléfono☎️\n",
    "\n",
    "Tu tarea es escribir un programa en Python que valide números de teléfono y determine si están en el formato correcto. Utiliza expresiones regulares y las funciones del módulo re para realizar esta validación. El formato válido para un número de teléfono debe cumplir con las siguientes reglas:\n",
    "\n",
    "- Debe tener exactamente 10 dígitos.\n",
    "- Puede estar en cualquiera de los siguientes formatos: \"123-456-7890\" o \"(123) 456-7890\" o \"123 456 7890\".\n",
    "\n",
    "La función `validar_numero_telefono(telefono)` retornará `True` en caso de que sea válida la contraseña o `False` en caso contrario."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import re\n",
    "\n",
    "def validar_numero_telefono(telefono):\n",
    "    pass\n",
    "\n",
    "# Lista de números de teléfono para validar\n",
    "numeros_telefono = [\n",
    "    \"123-456-7890\",\n",
    "    \"(123) 456-7890\",\n",
    "    \"123 456 7890\",\n",
    "    \"1234-567-890\",\n",
    "    \"(123 456-7890\",\n",
    "    \"4567-890\",\n",
    "]\n",
    "\n",
    "for telefono in numeros_telefono:\n",
    "    if validar_numero_telefono(telefono):\n",
    "        print(f\"'{telefono}' es un número de teléfono válido.\")\n",
    "    else:\n",
    "        print(f\"'{telefono}' no es un número de teléfono válido.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
