2  Manejo de texto.

La información en forma de texto es muy importante para muchos procesos y actividades cotidianas. Desde almacenar información personal hasta desplegar textos en formatos elegantes y vistosos. En esta sección se muestra cómo usar las cadenas para almacenar textos, darles formato, recibir información desde el teclado y enviar el contenido a archivos. Adicionalmente, en el Apéndice E encontrarás más detalles sobre este tema.

2.1 Cadenas

En Python, una cadena (string) es una secuencia de caracteres utilizada para representar texto. Las cadenas se pueden crear utilizando:

  • comillas simples ',
  • comillas dobles " o
  • comillas triples """ o '''.

Por ejemplo:

frase1 = "O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo"
frase2 = 'O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo'
frase3 = """O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo"""
frase4 = '''O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo'''

Todas las variables antes definidas son de tipo cadena y contienen lo mismo (pero son variables distintas):

print(frase1, frase2, frase3, frase4, sep="\n")
O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo
O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo
O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo
O ya no entiendo lo que está pasando o ya pasó lo que estaba yo entendiendo
print(type(frase1), type(frase2), type(frase3), type(frase4), sep="\n")
<class 'str'>
<class 'str'>
<class 'str'>
<class 'str'>

Es posible agregar caracteres especiales usando el caracter de escape \, por ejemplo si deseamos un cambio de línea en la cadena anterior agregamos \n donde se desee hacer el cambio de línea:

frase1 = "O ya no entiendo lo que está pasando \no ya pasó lo que estaba yo entendiendo"

print(frase1)
O ya no entiendo lo que está pasando 
o ya pasó lo que estaba yo entendiendo

Otro ejemplo:

frase1 = "Life is like a box of chocolates. \n\tYou never know what you\'re gonna get."

print(frase1)
Life is like a box of chocolates. 
    You never know what you're gonna get.

El el código anterior agregamos \n\t que representan un cambio de línea seguido de un tabulador. La documentación completa de caracteres especiales se puede encontrar en el siguiente enlace: Escape sequences.

Ejemplo 2.1: Definición de una cadena.

Escribe el siguiente código y ejecútalo:

ejemplo = 'Chiripitifláutico'

print(ejemplo)
print(type(ejemplo))

Chiripitifláutico: Algo muy bueno, de gran calidad (coloquial).

ejemplo = 'Chiripitifláutico'

print(ejemplo)
print(type(ejemplo))
Chiripitifláutico
<class 'str'>

Observa que la variable ejemplo es de tipo str.

Ejemplo 2.2: Indexación y slicing.

La cadena definida en el Ejemplo 2.1 tiene N = 17 elementos que se ven como sigue

C h i r i p i t i f l á u t i c o
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
-17 -16 -15 -14 -13 -12 -11 -10 -9 -8 -7 -6 -5 -4 -3 -2 -1

Sus índices positivos van de 0 a 16 y sus índices negativos van de -1 a -17.

Se puede acceder a los diferentes elementos de la cadena cómo se explica en la Sección E.3 y también es posible obtener una subcadena a partir de la cadena original usando la construcción: str[Start:End:Stride]

En los siguientes ejercicios, accederemos a diferentes elementos de la cadena ejemplo:

  1. Elemento 0.
  2. Elemento final con índice positivo y negativo.
  3. Elemento 5 con índice positivo y negativo.
  4. Obtener la subcadena pitifláu.
  5. Todos los elementos pares.
  6. Todos los elementos impares.
  7. Los elementos pares e impares de 2 a 12.
  8. Los elementos pares de toda la cadena en reversa.
# 1. elemento 0
ejemplo[0]
'C'
# 2. elemento final, índices positivo y negativo
ejemplo[-1]
'o'
# 3. elemento 5, índices positivo y negativo
ejemplo[5]
'p'
# 4. subcadena 'pitifláu'
ejemplo[5:13]
'pitifláu'
# 5. Elementos pares
ejemplo[::2]
'Ciiiiluio'
# 6. Elementos impares
ejemplo[1::2]
'hrptfátc'
# 7. Elementos pares de 2 a 12
ejemplo[2:13:2]
'iiiilu'
# 7. Elementos impares de 2 a 12
ejemplo[3:13:2]
'rptfá'
# 8. Elementos pares, toda la cadena, en reversa
ejemplo[::2][::-1]
'oiuliiiiC'
Ejemplo 2.3: Métodos.

A las cadenas les podemos aplicar métodos, veamos algunos ejemplos

Definir el siguiente texto y almacenarlo en la variable cadena:

Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
  1. Con triples comillas.
  2. Con dobles comillas.
  3. Extraer la primera línea del texto, sin el cambio de línea y asignarla a la variable linea1.
  4. Contar el número total de letras r en el texto.
  5. Imprimir linea1 centrada en 50 espacios, rellenando los espacios con el caracter *.
  6. Extraer la palabra interrumpir del texto.
  7. Extraer la palabra interrumpir del texto y luego convertir todas las letras a mayúsculas.
# 1. Triples comillas
cadena = """Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela"""

print(cadena)
Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
# 2. Dobles comillas
cadena = "Desde muy niño\ntuve que \"interrumpir\" 'mi' educación\npara ir a la escuela"""

print(cadena)
Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela

Recordemos cómo es la cadena para realizar el punto 3.

cadena = Desde muy niño\n
tuve que "interrumpir" 'mi' educación\n
para ir a la escuela
# 3.
# Encontrar el índice del primer cambio de línea.
cadena.find('\n')
14
# str[Start:End:Stride]
# Obtener la primera línea sin el cambio de línea usando slicing.
linea1 = cadena[0:14]

# Imprimir la línea
print(linea1)
Desde muy niño
# 4. contar las letras 'r'
cadena.count('r')
5
# 5. linea1, centrada, fill with *
linea1.center(50, '*')
'******************Desde muy niño******************'
# 6. extraer 'interrumpir'

# Calcular la longitud de la palabra "interrumpir"
print(len("interrumpir"))
11
# Encontrar el índice de las primeras comillas dobles
cadena.find('"')
24
# Extraer la palabra usando slicing con los índices calculados
cadena[25:25+11]
'interrumpir'
# 7. extraer 'interrumpir' y transformar a mayúsculas
# Realizar todo en una sola línea
cadena[cadena.find('"')+1:cadena.find('"')+12].upper()
'INTERRUMPIR'
Ejemplo 2.4: Funciones y operadores.

A las cadenas también les podemos aplicar funciones y operadores para transformarlas. Veamos algunos ejemplos

Usando la variable cadena definida en el ejemplo 3, realizar lo siguiente:

  1. Determinar la longitud total de cadena.
  2. Calcular el máximo y mínimo de cadena.
  3. Verificar si las palabras ir, qué, cuando y la están en cadena.
# 1. longitud de 'cadena'
len(cadena)
73
# 2. max y min de 'cadena'
max(cadena)
'ó'
min(cadena)
'\n'
# 3. Verificar: 'ir', 'qué', 'cuando', 'la', usando el operador 'in'
'ir' in cadena
True
Ejemplo 2.5: Caracteres unicode.

Imprimir el texto de la variable cadena, definida en el ejemplo 4, como sigue:

→→→→→→→→               😾                ←←←←←←←←
··················Desde muy niño··················
······tuve que "interrumpir" 'mi' educación·······
···············para ir a la escuela···············
                                               😹

El número total de caracteres de las tres líneas intermedias es de 50.

Hint. Checa los caracteres Unicode aquí: https://www.compart.com/en/unicode/html

print(cadena)
Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
# Paso a paso

# Índice del primer cambio de línea
fin_1 = cadena.find('\n')

# Índice del segundo cambio de línea
fin_2 = cadena.find('\n', fin_1+1)

# Imprimir los índices
print(fin_1, fin_2)
14 52
# Obtener las líneas usando slicing y los índices
linea1 = cadena[0:fin_1]
linea2 = cadena[fin_1+1:fin_2]
linea3 = cadena[fin_2+1:]

print(linea1)
print(linea2)
print(linea3)
Desde muy niño
tuve que "interrumpir" 'mi' educación
para ir a la escuela
# Checar los códigos Unicode de los caracteres
print(chr(0x2192), chr(0x1F63E), chr(0x1F639), chr(0x00B7))
→ 😾 😹 ·
# Repetir un caracter muchas veces
print(50 * chr(0x00B7))
··················································
# Primera línea
print(8*chr(0x2192), chr(0x1F63E).center(30), 8*chr(0x2190))

# Imprimir las tres líneas centradas rellenando espacios con .
print(linea1.center(50, chr(0x00B7)))
print(linea2.center(50, chr(0x00B7)) )
print(linea3.center(50, chr(0x00B7)) )

# Última línea
print(chr(0x1F639).rjust(48))
→→→→→→→→               😾                ←←←←←←←←
··················Desde muy niño··················
······tuve que "interrumpir" 'mi' educación·······
···············para ir a la escuela···············
                                               😹

2.2 Formato de salida.

2.2.1 Método str.format()

Este método permite sustituir variables en los lugares indicados por {}:

# Definimos algunas variables
nombre = "Hedy"
apellido = "Lamarr"
edad = 111
peso = 55.5

# Definimos unz cadena usando las variables anteriores.
datos = '{} {} cumpliría {} años en 2025'.format(nombre, apellido, edad)
print(datos)
Hedy Lamarr cumpliría 111 años en 2025

2.2.2 Cadenas formateadas (f-string, formatted string literals)

Este tipo de cadenas permite sustituir variables en los lugares indicados, por ejemplo:

datos = f'{nombre} {apellido} cumpliría {edad} años en 2025'
print(datos)
Hedy Lamarr cumpliría 111 años en 2025
Ejemplo 2.6: Texto formateado.

Generar la siguiente salida:

――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
         Nombre: Armand Gustav Duplantis
           Edad: 24
         Casado: 0
           Peso: 61.00
       Estatura:  1.81
  IMC (métrico): 18.62
   IMC (inglés): 18.62
――――――――――――――――――――――――――――――――――――――――――――――――――
  1. Usando el método str.format()
  2. Usando f-string.

Nota. El número total de caracteres en cada línea es de 50.

# Paso a paso

# Definir las variables
nombre = "Armand Gustav Duplantis"
casado = False
edad = 24
peso = 61 # kg
estatura = 1.81 # m

# Calcular IMC con el sistema métrico
IMC_metrico = peso / estatura**2

# Convertir a libras y pulgadas
peso_lb = peso * 2.20462
estatura_in = estatura * 39.3701

# Calcular el IMC con el sistema inglés
IMC_ingles = peso_lb / estatura_in**2 * 703
# Revisar el código Unicode de la línea continua
print(chr(0x2015))
# 1. Usando str.format()
print(50 * chr(0x2015))
print("Datos personales".center(50))
print(50 * chr(0x2015))
print("{:>15s}: {:<}".format("Nombre", nombre ))
print("{:>15s}: {:<}".format("Edad", edad))
print("{:>15s}: {:<}".format("Casado", casado))
print("{:>15s}: {:>5.2f}".format("Peso", peso))
print("{:>15s}: {:>5.2f}".format("Estatura", estatura))
print("{:>15s}: {:>5.2f}".format("IMC (métrico)", IMC_metrico))
print("{:>15s}: {:>5.2f}".format("IMC (inglés)", IMC_ingles))
print(50 * chr(0x2015))
――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
         Nombre: Armand Gustav Duplantis
           Edad: 24
         Casado: 0
           Peso: 61.00
       Estatura:  1.81
  IMC (métrico): 18.62
   IMC (inglés): 18.62
――――――――――――――――――――――――――――――――――――――――――――――――――
# 2. Usando f-string

# Definir las cadenas necesarias
snombre = "Nombre"
sedad = "Edad"
scasado = "Casado"
speso = "Peso"
sestatura = "Estatura"
sIMC_m = "IMC (métrico)"
sIMC_i = "IMC (inglés)"
# Imprimir
print(50 * chr(0x2015))
print("Datos personales".center(50))
print(50 * chr(0x2015))
print(f"{snombre:>15s}: {nombre:<}")
print(f"{sedad:>15s}: {edad:<}")
print(f"{scasado:>15s}: {casado:<}")
print(f"{speso:>15s}: {peso:>5.2f}")
print(f"{sestatura:>15s}: {estatura:>5.2f}")
print(f"{sIMC_m:>15s}: {IMC_metrico:>5.2f}")
print(f"{sIMC_i:>15s}: {IMC_ingles:>5.2f}")
print(50 * chr(0x2015))
――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
         Nombre: Armand Gustav Duplantis
           Edad: 24
         Casado: 0
           Peso: 61.00
       Estatura:  1.81
  IMC (métrico): 18.62
   IMC (inglés): 18.62
――――――――――――――――――――――――――――――――――――――――――――――――――
# Otra opción usando str.format()
formato1 = "{:>15s}: {:<}"
formato2 = "{:>15s}: {:>5.2f}"
linea = 50 * chr(0x2015)

print(linea)
print("Datos personales".center(50))
print(linea)
print(formato1.format("Nombre", nombre))
print(formato1.format("Edad", edad))
print(formato1.format("Casado", casado))
print(formato2.format("Peso", peso))
print(formato2.format("Estatura", estatura))
print(formato2.format("IMC (métrico)", IMC_metrico))
print(formato2.format("IMC (inglés)", IMC_ingles))
print(linea)
――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
         Nombre: Armand Gustav Duplantis
           Edad: 24
         Casado: 0
           Peso: 61.00
       Estatura:  1.81
  IMC (métrico): 18.62
   IMC (inglés): 18.62
――――――――――――――――――――――――――――――――――――――――――――――――――

2.3 Entrada estándar.

En Python es posible proporcionar información a un código mediante la función incorporada input(). Por ejemplo:

input("Teclea un número:")
Teclea un número: 6
'6'

Observaciones. * La cadena entre los paréntesis proporciona información para saber lo que se debe teclear. Esta cadena se conoce como prompt. * Esta cadena se imprime cuando se ejecuta la función input() y luego se espera a que teclees alguna información. * Cuando se teclea <enter> la función input() lee la información proporcionada. * Input lee toda la información en formato de cadena (str). * La información que se teclea se puede almacenar en una variable.

numero = input("Teclea un número:")
print("El número que tecleaste fue:", numero)
Teclea un número: 9
El número que tecleaste fue: 9
Ejemplo 2.7: Entrada de datos y cálculo con esos datos.

Escribe un código que solicite al usuario su nombre, su edad, su peso y su estatura. Con esa información el código deberá calcular el índice de masa corporal y generar una salida como la siguiente:

Escribe tu nombre: Luis Miguel
Escribe tu edad: 25
Escribe tu peso: 80
Escribe tu estatura: 1.75

Hola Luis Miguel (25), tu índice de masa corporal es 26.122

¿Qué pasa con el siguiente código?

nombre = input('Escribe tu nombre:')
edad = input('Escribe tu edad:')
peso = input('Escribe tu peso:')
estatura = input('Escribe tu estatura:')
imc = peso / estatura**2
print(f"\nHola {nombre} ({edad}), tu índice de masa corporal es {imc:6.3f}")
Escribe tu nombre: Carl
Escribe tu edad: 75
Escribe tu peso: 75
Escribe tu estatura: 1.70
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[46], line 5
      3 peso = input('Escribe tu peso:')
      4 estatura = input('Escribe tu estatura:')
----> 5 imc = peso / estatura**2
      6 print(f"\nHola {nombre} ({edad}), tu índice de masa corporal es {imc:6.3f}")

TypeError: unsupported operand type(s) for ** or pow(): 'str' and 'int'

El código anterior genera un error de tipo TypeError y se debe a que se está intentando realizar una operación no compatible con una cadena y un entero. Para que el código funcione, se deben convertir los números que se usan en operaciones en los tipos numéricos correspondientes. En este ejemplo se debe hacer lo siguiente:

nombre = input('Escribe tu nombre:')
edad = int(input('Escribe tu edad:'))
peso = float(input('Escribe tu peso:'))
estatura = float(input('Escribe tu estatura:'))
imc = peso / estatura**2
print(f"\nHola {nombre} ({edad}), tu índice de masa corporal es {imc:6.3f}")
Escribe tu nombre: Carl
Escribe tu edad: 75
Escribe tu peso: 80
Escribe tu estatura: 1.70

Hola Carl (75), tu índice de masa corporal es 27.682

2.4 Gestión de archivos.

La función incorporada para gestionar archivos es open(). Esta función toma dos parámetros: el nombre del archivo y el modo. Existen cuatro diferentes modos:

  • "r" - Read - Abre el archivo para lectura. Se produce un error si el archvio no existe. Valor por omisión.
  • "a" - Append - Abre el archivo para agregar información. Si el archivo no existe, lo crea.
  • "w" - Write - Abre el archivo para escritura. Si el archivo no existe, lo crea. Si el archivo existe, lo sobreescribe.
  • "x" - Create - Crea el archivo, regresa un error si el archivo existe.

Adicionalmente se puede especificar si el archivo se abre en modo texto o binario:

  • "t" - Text - Valor por omisión.
  • "b" - Binary
Ejemplo 2.8: Abrir un archivo y leer la información.

El archivo personal_data.csv contiene la siguiente información:

Id S E Pe A IMC Di H De TS TA
Sexo Edad Peso Altura Índice de masa corporal Diabetes Hipertensión Depresión Trastorno del sueño Trastorno de la alimentación

Los datos en el archivo están separados por coma (CSV, Comma-Separated Values).

Escribe un código que haga lo siguiente:

  1. Abrir el archivo personal_data.csv para lectura.
  2. Leer el encabezado del archivo.
  3. Leer los datos de los primeros 3 renglones.
  4. Calcular el IMC con los datos obtenidos del primer renglón.
  5. Comparar con la información del IMC del archivo.
# 1. Abrir el archivo en modo lectura
f = open("personal_data.csv", "r")

# 2. Leemos el encabezado
encabezado = f.readline()

# 3. Leemos las primeras 5 líneas del archivo
renglon_1 = f.readline()
renglon_2 = f.readline()
renglon_3 = f.readline()

# Imprimimos información obtenida.
print(encabezado, renglon_1, renglon_2, renglon_3)
print(type(encabezado), type(renglon_1), type(renglon_2), type(renglon_3))

# Cerrar el archivo
f.close()
Id,S,E,Pe,A,IMC,Di,H,De,TS,TA
 1,h,35,75,1.7,25.95,Si,Si,No,No,Si
 2,m,57,88,1.59,34.81,No,Si,No,No,No
 3,h,40,81,1.66,29.39,No,No,No,Si,No

<class 'str'> <class 'str'> <class 'str'> <class 'str'>

Observa que se usa el método readline() para leer un renglón del archivo. El resultado es una cadena que se almacena en las diferentes variables. Los datos están separados por comas , por lo que debemos separarlos, esto lo hacemos con el método split():

# Separamos las líneas por las comas
encabezado = encabezado.split(sep=',')
renglon_1 = renglon_1.split(sep=',')
renglon_2 = renglon_2.split(sep=',')
renglon_3 = renglon_3.split(sep=',')

print(encabezado, renglon_1, renglon_2, renglon_3, sep='\n')
print(type(encabezado), type(renglon_1), type(renglon_2), type(renglon_3))
['Id', 'S', 'E', 'Pe', 'A', 'IMC', 'Di', 'H', 'De', 'TS', 'TA\n']
['1', 'h', '35', '75', '1.7', '25.95', 'Si', 'Si', 'No', 'No', 'Si\n']
['2', 'm', '57', '88', '1.59', '34.81', 'No', 'Si', 'No', 'No', 'No\n']
['3', 'h', '40', '81', '1.66', '29.39', 'No', 'No', 'No', 'Si', 'No\n']
<class 'list'> <class 'list'> <class 'list'> <class 'list'>

En el código anterior se utilizó el método str.split() para separar cada cadena en subcadenas; este método almacena el resultado en una lista. La lista se puede indexar de la misma forma en que se indexan las cadenas, véase la sección Sección E.3 para más información.

El tema de listas se puede revisar con detalle en el Apéndice I.

Obtenemos los datos del peso, estatura e imc usando indexación de las listas:

peso = renglon_1[3]
estatura = renglon_1[4]
imc_db = renglon_1[5]

print(peso, estatura, imc_db)
print(type(peso), type(estatura), type(imc_db))
75 1.7 25.95
<class 'str'> <class 'str'> <class 'str'>

Observa que los datos están en formato cadena, por lo que debemos convertirlos a un formato numérico para poder usarlos en cálculos numéricos:

# 4. Calculamos el IMC (debemos convertir a flotantes antes de hacer el cálculo)
IMC = float(peso) / float(estatura)**2
print(IMC)
25.95155709342561
# 5. Comparamos el cálculo con los datos del archivo
print(f"IMC DB = {float(imc_db):5.5f} \t IMC = {IMC:5.5f}")

iguales = float(imc_db) == IMC
print(f"¿Son iguales? {iguales}")
IMC DB = 25.95000    IMC = 25.95156
¿Son iguales? False
# Una forma más adecuada de comparar números flotantes
from math import isclose

iguales = isclose(float(imc_db), IMC, rel_tol=1e-4)

print(f"¿Son iguales? {iguales}")
¿Son iguales? True
NotaNota.

Más información sobre archivos la puedes revisar en el Apéndice G.

2.5 Proyecto.

Ejemplo 2.9: Índice de masa corporal.

Deasrrollar un programa que realice lo siguiente:

  1. Leer la información del archivo personal_data.csv que contiene la información que se describe en el Ejemplo 2.8.
  2. Solicitar al usario el Id de un paciente y desplegar la información de ese paciente como sigue:
Id :  38

――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
             Id: 38
            Nom: Pedro
            Ape: García
              S: h
              E: 35
             Pe: 84.000
              A:  1.780
            IMC: 26.510
           IMCi: 26.509
             Di: No
              H: Si
             De: Si
             TS: Si
             TA: No
――――――――――――――――――――――――――――――――――――――――――――――――――
  1. Observa que en el archivo no se encuentra la información del nombre y apellido, y tampoco el IMCi que representa el IMC calculado usando el sistema inglés. Esta información se debe generar de la siguiente manera:
    1. Generar nombre y apellido de manera aleatoria, tanto para mujeres como para hombres.
    2. Calcular el IMCi usando los valores del peso y estatura del archivo.
    3. Estos datos se deben agregar al encabezado del archivo y a cada renglón de información.
  2. Guardar el archivo del paciente consultado con toda la información generada. El nombre del archivo debe ser paciente_00.csv donde 00 se debe sustituir por el Id del paciente.

2.5.1 Paso 1. Lectura de archivo.

Lo primero que se debe realizar es leer la información del archivo. Esto se hace usando un gestor de contexto como sigue:

# Abrimos el archivo y leemos la información.
with open("personal_data.csv", "r") as f:
    renglones = f.readlines()

En el código anterior la declaración with permite abrir el archivo en modo lectura definiendo el descriptor de archivo f; con ese descriptor se lee la información del archivo con el método readlines() y se almacena en la variable renglones; terminando la declaración with el archivo se cierra automáticamente. Esta es la ventaja de los gestores de contexto: inicializan un recurso (en este caso un archivo), lo usan y lo liberan automáticamente. Para saber más revisa la Sección G.9.

En la variable renglones se tiene toda la información del archivo, veamos de qué tipo es esta variable:

print(type(renglones))
<class 'list'>

La variable renglones es de tipo lista. Una lista es una secuencia que se puede recorrer mediante ciclos. A continuación usamos la declaración for que permite realizar un ciclo en donde las operaciones se repiten:

# Mostramos los primeros tres renglones de datos
for r in renglones[1:4]:
    print(r)
1,h,35,75,1.7,25.95,Si,Si,No,No,Si

2,m,57,88,1.59,34.81,No,Si,No,No,No

3,h,40,81,1.66,29.39,No,No,No,Si,No

En el ciclo for anterior se usa la variable r para almacenar los valores que se van obteniendo de la secuencia renglones, que en este caso es una lista. Mediante la indexación solo se accede a los tres primeros elementos de la lista ([1:4]). Durante cada iteración del ciclo for solo se imprime cada renglón que se va obteniendo usando la función print(). Más información sobre el ciclo for y otras herramientas de control de flujo se puede encontrar en el Apéndice H.

Podemos conocer el total de renglones que se leyeron del archivo usando la función len():

len(renglones)
101

2.5.2 Paso 2. Procesamiento del encabezado.

Ahora veamos el primer renglón que contiene información del encabezado de los datos:

print(renglones[0], type(renglones[0]), id(renglones[0]))
Id,S,E,Pe,A,IMC,Di,H,De,TS,TA
 <class 'str'> 1572858057696

Observaciones:

  • Usamos indexado para acceder al primer renglón del archivo ([0]).
  • Los datos están separados por coma.
  • Cada renglón es una cadena.
  • Al final de cada renglón se encuentra el caracter de cambio de línea: \n.

Separación de la información.

Los datos se pueden separar usando el método split(). Inicamos que se haga la separación por las comas (,):

encabezado = renglones[0].split(",")

print(encabezado, type(encabezado), id(encabezado))
['Id', 'S', 'E', 'Pe', 'A', 'IMC', 'Di', 'H', 'De', 'TS', 'TA\n'] <class 'list'> 1572857508800

El método split() genera una lista con los elementos separados.

Insertamos datos adicionales.

Utilizamos el método insert() para agregar las columnas del nombre, apellido y el IMC en sistema inglés, en los lugares correspondientes.

# Insertamos la columna para el nombre
encabezado.insert(1, "Nom")
print(encabezado)
['Id', 'Nom', 'S', 'E', 'Pe', 'A', 'IMC', 'Di', 'H', 'De', 'TS', 'TA\n']
# Insertamos la columna para el apellido
encabezado.insert(2, "Ape")
print(encabezado)
['Id', 'Nom', 'Ape', 'S', 'E', 'Pe', 'A', 'IMC', 'Di', 'H', 'De', 'TS', 'TA\n']
# Insertamos la columna para el IMC en sistema inglés
encabezado.insert(8, "IMCi")
print(encabezado)
['Id', 'Nom', 'Ape', 'S', 'E', 'Pe', 'A', 'IMC', 'IMCi', 'Di', 'H', 'De', 'TS', 'TA\n']

Observamos que el último elemento de la lista contiene un cambio de línea. Lo podemos eliminar como sigue:

# Eliminamos el cambio de línea en el último elemento de la lista
encabezado[-1] = encabezado[-1][:-1]
print(encabezado)
['Id', 'Nom', 'Ape', 'S', 'E', 'Pe', 'A', 'IMC', 'IMCi', 'Di', 'H', 'De', 'TS', 'TA']

2.5.3 Paso 3. Procesamiento de la información.

Para cada renglón del archivo necesitamos agregar los datos del nombre, apellido e IMC en sistema inglés. El nombre y el apellido los generamos de manera aleatoria usando una función como se muestra a continuación:

Generación de nombres.

# Biblioteca generadora de variables aleatorias
import random

def genera_nombre(sexo):
    # Definimos listas de nombres y apellidos
    nombres_mas =  ["Juan", "Carlos", "Luis", "Gabriel", 
                    "Pedro", "Gustavo", "Samuel", "Noé"]
    nombres_fem =  ["Ana",  "María", "Juana", "Luisa", 
                    "Angélica", "Mónica", "Diana", "Julia" ]
    apellidos = ["Gómez", "Pérez", "López", "García", "Sánchez", 
                 "Vázquez", "Barrios", "Soler", "Márquez", "Villoro"]

    # Dependiendo del sexo se determina el nombre correspondiente de manera aleatoria.
    if sexo == "h":
        nombre = f"{random.choice(nombres_mas)}" 
    elif sexo == "m":
        nombre = f"{random.choice(nombres_fem)}" 

    # Se determina el apellido
    apellido = f"{random.choice(apellidos)}"

    # Se regresa el nombre y apellido en una tupla
    return (nombre, apellido)

Probamos la función para cuando el paciente es hombre “h” y cuando es mujer “m”:

genera_nombre('h')
('Juan', 'Sánchez')
genera_nombre('m')
('Ana', 'Barrios')

Por ahora no explicaremos mucho sobre la función, solo diremos que para ejecutarla se usa el nombre de la función y se pasa entre paréntesis el argumento correspondiente, en este caso un caracter que indica si el paciente es hombre o mujer. La función regresa un par de cadenas, la primera es el nombre y la segunda es el apellido. Esta función será usada más adelante. Más acerca de funciones se puede ver en el Apéndice O.

Separación de los renglones.

La información de cada renglón debe separarse para ser procesada. En lo que sigue haremos una prueba con el renglón \(1\).

# Separación en una lista
renglon = renglones[1].split(",")

print(renglon, type(renglon))
['1', 'h', '35', '75', '1.7', '25.95', 'Si', 'Si', 'No', 'No', 'Si\n'] <class 'list'>

Transformar texto en números.

Algunos de los datos son números, pero están en formato de cadena, veamos esto con el siguiente ciclo:

for r in renglon:
    print(r, type(r))
1 <class 'str'>
h <class 'str'>
35 <class 'str'>
75 <class 'str'>
1.7 <class 'str'>
25.95 <class 'str'>
Si <class 'str'>
Si <class 'str'>
No <class 'str'>
No <class 'str'>
Si
 <class 'str'>

Transformamos los datos correspondientes en tipos numéricos:

renglon[0] = int(renglon[0])   # Id
renglon[2] = int(renglon[2])   # Edad
renglon[3] = float(renglon[3]) # Peso
renglon[4] = float(renglon[4]) # Estatura
renglon[5] = float(renglon[5]) # IMC

Revisamos el resultado con el siguiente ciclo:

for r in renglon:
    print(r, type(r))
1 <class 'int'>
h <class 'str'>
35 <class 'int'>
75.0 <class 'float'>
1.7 <class 'float'>
25.95 <class 'float'>
Si <class 'str'>
Si <class 'str'>
No <class 'str'>
No <class 'str'>
Si
 <class 'str'>

Eliminar cambio de línea.

# Eliminamos el cambio de línea del último elemento.
renglon[-1] = renglon[-1][:-1]

for r in renglon:
    print(r, type(r))
1 <class 'int'>
h <class 'str'>
35 <class 'int'>
75.0 <class 'float'>
1.7 <class 'float'>
25.95 <class 'float'>
Si <class 'str'>
Si <class 'str'>
No <class 'str'>
No <class 'str'>
Si <class 'str'>

Agregamos la información requerida.

# Generamos el nombre y apellido
nombre, apellido = genera_nombre(renglon[1])

# Convertimos a libras y pulgadas
peso_lb = renglon[3] * 2.20462
estatura_in = renglon[4] * 39.3701

# Calculamos el IMC con el sistema inglés
IMCi = peso_lb / estatura_in**2 * 703

# Insertamos nombre y apellido en la lista
renglon.insert(1, nombre)
renglon.insert(2, apellido)

# Insertamos el IMCi en la columna correspondiente
renglon.insert(8, IMCi)

print(renglon)
[1, 'Gabriel', 'García', 'h', 35, 75.0, 1.7, 25.95, 25.94892989965333, 'Si', 'Si', 'No', 'No', 'Si']

2.5.4 Paso 4. Despliegue de la información,

Vamos a imprimir la información generada usando la función str.format() como sigue:

formato1 = "{:>15s}: {:<}"
formato2 = "{:>15s}: {:>6.3f}"
linea = 50 * chr(0x2015)
    
print(linea)
print(f"Datos personales".center(50))
print(linea)
print(formato1.format(encabezado[0], renglon[0]))
print(formato1.format(encabezado[1], renglon[1]))
print(formato1.format(encabezado[2], renglon[2]))
print(formato1.format(encabezado[3], renglon[3]))
print(formato1.format(encabezado[4], renglon[4]))
print(formato2.format(encabezado[5], renglon[5]))
print(formato2.format(encabezado[6], renglon[6]))
print(formato2.format(encabezado[7], renglon[7]))
print(formato2.format(encabezado[8], renglon[8]))
print(formato1.format(encabezado[9], renglon[9]))
print(formato1.format(encabezado[10], renglon[10]))
print(formato1.format(encabezado[11], renglon[11]))
print(formato1.format(encabezado[12], renglon[12]))
print(formato1.format(encabezado[13], renglon[13]))
print(linea)
――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
             Id: 1
            Nom: Gabriel
            Ape: García
              S: h
              E: 35
             Pe: 75.000
              A:  1.700
            IMC: 25.950
           IMCi: 25.949
             Di: Si
              H: Si
             De: No
             TS: No
             TA: Si
――――――――――――――――――――――――――――――――――――――――――――――――――

2.5.5 Paso 5. Guardar la información en el archivo.

# Definimos la variable Id (esta será dada por el usuario en el último paso del proyecto)
Id = 1

# Generamos el nombre del archivo que debe tener el formato: 'paciente_00.csv'
archivo_paciente = f"paciente_{Id:02d}.csv"

# Abrimos el archivo en modo escritura.
with open(archivo_paciente, "w", encoding="utf-8") as f:

    # Convertimos a cadena toda la información que se ha procesado al momento
    for i, v in enumerate(renglon):
        renglon[i] = str(renglon[i])

    # Escribimos la información al archivo
    f.writelines([",".join(encabezado) + "\n",
                  ",".join(renglon) + "\n"])

print(f"Archivo creado: {archivo_paciente}")
Archivo creado: paciente_01.csv

Recordemos que tenemos la lista encabezado con la información de cada columna del archivo y la lista renglon con la información del paciente con Id = 1. Para escribir la información en el archivo usamos el método writelines() que recibe una lista de cadenas y las escribe una por una. Observa que agregamos caracteres de cambio de línea para almacenar la información por renglones. Usamos el método join() que junta una lista de cadenas en una sola, separando cada cadena por el caracter que se indica, en este caso por comas (,), de esta manera generamos un archivo de tipo CSV. Finalmente, al abrir el archivo usamos encoding="utf-8" de esta manera se asegura que el archivo es creado con la codificación UTF8 y no tendrá problemas con caracteres especiales, particularmente con las letras con acento.

# Verificamos el contenido del archivo.
with open(archivo_paciente, "r", encoding="utf-8") as f:
    for r in f:
        print(r)
Id,Nom,Ape,S,E,Pe,A,IMC,IMCi,Di,H,De,TS,TA

1,Gabriel,García,h,35,75.0,1.7,25.95,25.94892989965333,Si,Si,No,No,Si

2.5.6 Paso 6. Juntando todo.

Aquí juntamos todos los pasos anteriores y agregamos una línea de código para introducir el Id del paciente mediante la función input():

# Abrimos el archivo y leemos la información.
with open("personal_data.csv", "r", encoding="utf-8") as f:
    renglones = f.readlines()

encabezado = renglones[0].split(",")
encabezado.insert(1, "Nom")
encabezado.insert(2, "Ape")
encabezado.insert(8, "IMCi")
encabezado[-1] = encabezado[-1][:-1]

Id = int(input("Id : "))

renglon = renglones[Id].split(",")
renglon[0] = int(renglon[0])   # Id
renglon[2] = int(renglon[2])   # Edad
renglon[3] = float(renglon[3]) # Peso
renglon[4] = float(renglon[4]) # Estatura
renglon[5] = float(renglon[5]) # IMC
renglon[-1] = renglon[-1][:-1]

# Generamos el nombre y apellido
nombre, apellido = genera_nombre(renglon[1])

# Convertimos a libras y pulgadas
peso_lb = renglon[3] * 2.20462
estatura_in = renglon[4] * 39.3701

# Calculamos el IMC con el sistema inglés
IMCi = peso_lb / estatura_in**2 * 703

# Insertamos nombre y apellido en la lista
renglon.insert(1, nombre)
renglon.insert(2, apellido)

# Insertamos el IMCi en la columna correspondiente
renglon.insert(8, IMCi)

formato1 = "{:>15s}: {:<}"
formato2 = "{:>15s}: {:>6.3f}"
linea = 50 * chr(0x2015)

print(linea)
print(f"Datos personales".center(50))
print(linea)
print(formato1.format(encabezado[0], renglon[0]))
print(formato1.format(encabezado[1], renglon[1]))
print(formato1.format(encabezado[2], renglon[2]))
print(formato1.format(encabezado[3], renglon[3]))
print(formato1.format(encabezado[4], renglon[4]))
print(formato2.format(encabezado[5], renglon[5]))
print(formato2.format(encabezado[6], renglon[6]))
print(formato2.format(encabezado[7], renglon[7]))
print(formato2.format(encabezado[8], renglon[8]))
print(formato1.format(encabezado[9], renglon[9]))
print(formato1.format(encabezado[10], renglon[10]))
print(formato1.format(encabezado[11], renglon[11]))
print(formato1.format(encabezado[12], renglon[12]))
print(formato1.format(encabezado[13], renglon[13]))
print(linea)

# Generamos el nombre del archivo.
archivo_paciente = f"paciente_{Id:02d}.csv"

# Abrimos el archivo en modo escritura.
with open(archivo_paciente, "w", encoding="utf-8") as f:

    # Convertimos a cadena toda la información
    for i, v in enumerate(renglon):
        renglon[i] = str(renglon[i])

    # Escribimos la información al archivo
    f.writelines([",".join(encabezado) + "\n",
                  ",".join(renglon) + "\n"])

print(f"Archivo generado: {archivo_paciente}")
Id :  67
――――――――――――――――――――――――――――――――――――――――――――――――――
                 Datos personales                 
――――――――――――――――――――――――――――――――――――――――――――――――――
             Id: 67
            Nom: Noé
            Ape: Soler
              S: h
              E: 49
             Pe: 88.000
              A:  1.700
            IMC: 30.450
           IMCi: 30.447
             Di: No
              H: Si
             De: No
             TS: No
             TA: No
――――――――――――――――――――――――――――――――――――――――――――――――――
Archivo generado: paciente_67.csv
# Verificamos el contenido del archivo.
with open(archivo_paciente, "r", encoding="utf-8") as f:
    for r in f:
        print(r)
Id,Nom,Ape,S,E,Pe,A,IMC,IMCi,Di,H,De,TS,TA

67,Noé,Soler,h,49,88.0,1.7,30.45,30.44674441559324,No,Si,No,No,No