In [4]:
"""
IPython Notebook v4.0 para python 2.7
Librerías adicionales: Ninguna.
Contenido bajo licencia CC-BY 4.0. Código bajo licencia MIT. (c) Sebastian Flores.
"""

# Configuracion para recargar módulos y librerías 
%reload_ext autoreload
%autoreload 2

from IPython.core.display import HTML

HTML(open("style/iwi131.css", "r").read())


Out[4]:






IWI131

Programación de Computadores

Sebastián Flores

http://progra.usm.cl/

https://www.github.com/usantamaria/iwi131

¿Qué contenido aprenderemos?

  • Leer archivos de texto
  • Escribir un archivo de texto
  • Agregar contenido a un archivo ya existente

¿Porqué aprenderemos ese contenido?

  • Leer archivos de texto
  • Escribir un archivo de texto
  • Agregar contenido a un archivo ya existente

Read, Write y Append son las 3 acciones necesarias para trabajar con archivos de datos, tarea altamente habitual en el mundo real.

Desafío de la clase anterior

Desarrolle un programa que tome cualquier número e indique los dígitos que le faltan en orden.


In [6]:
def digitos_faltantes(numero):
    digitos_presentes = set(list(str(numero)))
    digitos_todos = set(map(str, range(10)))
    digitos_que_faltan = digitos_todos - digitos_presentes
    digitos_que_faltan = list(digitos_que_faltan)
    digitos_que_faltan.sort()
    return "".join(digitos_que_faltan)

def estan_todos_los_digitos(numero):
    digitos_presentes = set(list(str(numero)))
    digitos_todos = set(map(str, range(10)))
    digitos_que_faltan = digitos_todos - digitos_presentes
    if len(digitos_que_faltan)==0:
        print "No faltan digitos"
    else:
        print "Faltan {0} digitos".format(len(digitos_que_faltan))
    return

mi_numero = int(raw_input("Ingrese un numero: "))
print digitos_faltantes(mi_numero)
e-stan_todos_los_digitos(mi_numero)


Ingrese un numero: 9876543210

No faltan digitos
None

Clases

  • Lun 28 Dic 2016: Escribir y leer archivos.
  • Mie 30 Dic 2016: Ejercicios tipo certamen.
  • Lun 04 Ene 2016: Ejercicios tipo certamen.
  • Mie 06 Ene 2016: Actividad 5.

Consejo: Baje el libro del curso, lea, aprenda y practique.

Motivación para Archivos de Texto

¿Cómo podríamos hacer un programa que tomara un archivo y contara?

  • Número de letras
  • Número de palabras
  • Número de líneas

Archivo de ejemplo

En la carpeta data/ existe el archivo quijjote.txt que tiene el siguiente contenido:

En un lugar de la Mancha
de cuyo nombre no quiero acordarme
no ha mucho tiempo que vivia un hidalgo
de los de lanza en astillero
adarga antigua, rocin flaco y galgo corredor.

Procesaremos este archivo como ejemplo.

1. Lectura de archivo

Para abrir un archivo para lectura utilizamos el método open

open(string_con_direccion_al_archivo)

o bien

open(string_con_direccion_al_archivo, "r")

donde el carácter "r" se indica para lectura (read).

OBS: Cada línea vendrá con el carácter "\n" de manera explícita.


In [16]:
# Abrir el archivo
archivo = open('data/quijote.txt')
# Leer linea a linea, como si fuera una lista de lineas
for linea in archivo:
    print linea[:-1], #.replace("\n","")
    #print linea.replace("\n","~")
# Cerrar el archivo 
archivo.close()


En un lugar de la Mancha de cuyo nombre no quiero acordarme no ha mucho tiempo que vivia un hidalgo de los de lanza en astillero adarga antigua, rocin flaco y galgo corredor.

2. Escritura de archivo

Para abrir un archivo para escritura utilizamos el mismo metodo open pero con un carácter adicional "w" (write).

open(string_con_direccion_al_archivo, "w")

Luego le agregamos con el metodo write.

write(string_a_escribir_en_archivo)

OBS: Es necesario indicar los saltos de línea con "\n" de manera explícita. De lo contrario, seguiremos escribiendo siempre en la misma línea.


In [23]:
archivo = open('QUIJOTE.txt', 'w')
archivo.write('En un lugar de La Mancha\n'.upper())
archivo.write('de cuyo nombre\n'.upper())
archivo.write('no quiero acordarme\n'.upper())
archivo.write('no ha mucho tiempo\n'.upper())
archivo.write('que vivia un hidalgo\n'.upper())
archivo.close()

2. Escritura de archivo

OBSERVACION

Los archivos quedan por defecto en el directorio en el cual se ejecuta el archivo python (o de donde se lanzó python).

archivo = open('QUIJOTE.txt', 'w')

es distinto a

archivo = open('mi_carpeta/QUIJOTE.txt', 'w')

y es distinto a

archivo = open('mi_carpeta\QUIJOTE.txt', 'w')

3. Anexar contenido a un archivo

Para abrir un archivo para agregar contenido a un archivo ya existente utilizamos el método open pero con un caracter adicional "a" (append).

open(string_con_direccion_al_archivo, "a")

Luego le agregamos líneas con el método write.

write(string_a_escribir_en_archivo)

OBS: Es necesario indicar los saltos de línea con "\n" de manera explícita. De lo contrario, seguiremos escribiendo siempre en la misma línea.


In [25]:
archivo = open('QUIJOTE.txt', 'a')
archivo.write('de los de lanza en astillero\n'.upper())
archivo.write('adarga antigua, rocin flaco '.upper())
archivo.write('y galgo corredor.\n'.upper())
archivo.close()

Ejercicio 1: Motivación

¿Cómo podríamos hacer un programa tomara un archivo y que contara?

  • Número de letras
  • Número de palabras
  • Número de líneas

Ejercicio 1: Motivación: Análisis

¿Qué tareas son necesarias?


In [ ]:
def contar(path_al_archivo):
    archivo = open(path_al_archivo)
    n_lineas, n_caracteres, n_palabras = 0, 0, 0
    for linea in archivo:
        
        pass
    archivo.close()
    return n_lineas, n_caracteres, n_palabras

mi_archivo = "data/quijote.txt"
print contar(mi_archivo)


mi_archivo = "data/alumnos.txt"
print contar(mi_archivo)

Ejercicio 1: Solución


In [26]:
def contar(path_al_archivo):
    archivo = open(path_al_archivo)
    n_lineas = 0
    n_caracteres = 0
    n_palabras = 0
    for linea in archivo:
        # Contar lineas
        n_lineas += 1
        # Contar palabras
        n_palabras += len(linea.split()) 
        # Contar caracteres
        n_caracteres += len(linea)
    archivo.close()
    return n_lineas, n_caracteres, n_palabras

template = "El archivo {0} tiene {1} lineas, {2} caracteres y {3} palabras"

mi_archivo = "data/quijote.txt"
l,c,p = contar(mi_archivo)
print template.format(mi_archivo, l, c, p)

mi_archivo = "data/alumnos.txt"
l,c,p = contar(mi_archivo)
print template.format(mi_archivo, l, c, p)


El archivo data/quijote.txt tiene 5 lineas, 175 caracteres y 33 palabras
El archivo data/alumnos.txt tiene 5 lineas, 124 caracteres y 6 palabras

Archivo de ejemplo

En la carpeta data/ existe el archivo alumnos.txt que tiene el siguiente contenido:

Esteban:Gutierrez:49:18:32
Luisa:Miranda:68:44:99
Jean Paul:Munoz:48:38:81
Gianfranco:Basso:54:54:50
Romina:Smith:100:98:92

Se nos pide procesar este nuevo archivo.

Este archivo tiene la dificultad que los datos están separados por ":".

OBS: ¿Porqué es necesario utilizar el separador :?

Leer y escribir archivos con separador

El procesamiento de archivos con separador es tan simple como utilizar el método apropiado:

linea.split(":")

Donde obviamente necesitamos conocer el separador de antemando.

La escritura de archivos con separador requiere contar con una lista de strings, y luego utilizar el método join de manera apropiada:

":".join(lista_de_strings)

Ejemplo: Leer archivos con separador


In [27]:
archivo = open('data/alumnos.txt')
for linea in archivo:
    print linea
    valores = linea.split(':')
    print valores
    nombres = valores[0:2]
    notas = map(int, valores[2:5])
    print nombres[0], notas
archivo.close()


Esteban:Gutierrez:49:18:32

['Esteban', 'Gutierrez', '49', '18', '32\n']
Esteban [49, 18, 32]
Luisa:Miranda:68:44:99

['Luisa', 'Miranda', '68', '44', '99\n']
Luisa [68, 44, 99]
Jean Paul:Munoz:48:38:81

['Jean Paul', 'Munoz', '48', '38', '81\n']
Jean Paul [48, 38, 81]
Gianfranco:Basso:54:54:50

['Gianfranco', 'Basso', '54', '54', '50\n']
Gianfranco [54, 54, 50]
Romina:Smith:100:98:92

['Romina', 'Smith', '100', '98', '92\n']
Romina [100, 98, 92]

Ejemplo: Escribir archivos con separador


In [ ]:
# Generacion de datos
alumnos = [ ("Esteban","Gutierrez",49,18,32),
            ("Luisa","Miranda",68,44,99),
            ("Jean Paul","Munoz",48,38,81),
            ("Gianfranco","Basso",54,54,50),
            ("Romina","Smith",100,98,92)]
# Cerrar el archivo 
archivo = open("data/alumnos.txt", 'w')
# Crear lineas y escribirlas
for alumno in alumnos:
    valores = []
    for dato in alumno:
        valores.append(str(dato))
    linea = ':'.join(valores) + '\n'
    archivo.write(linea)
# Cerrar el archivo 
archivo.close()

Ejercicio 2

A partir del archivo alumnos.txt generar 2 archivos:

data/aprobados.txt

Luisa,Miranda,70
Jean Paul,Munoz,56
Romina,Smith,97

data/reprobados.txt

Esteban,Gutierrez,33
Gianfranco,Basso,53

Ejercicio 2 : Análisis

¿Que tareas son necesarias? ¿En cuál orden?


In [ ]:
# Ejemplo de lectura a modificar
archivo = open('data/alumnos.txt')
for linea in archivo:
    valores = linea.strip().split(':')
    nombres = valores[0:2]
    notas = map(int, valores[2:5])
    print nombres[0], notas
    
archivo.close()

Ejercicio 2 : Solución

¿Qué tareas son necesarias?

  • Leer archivo de alumnos
  • Procesar nombres y notas
  • Calcular promedio de notas
  • Calcular promedio final (redondeo)
  • Crear la linea a escribir
  • Escribir en el archivo apropiado

In [28]:
archivo = open('data/alumnos.txt')
aprobados = open('data/aprobados.txt',"w")
reprobados = open('data/reprobados.txt',"w")
template = "{0},{1},{2}\n"
for linea in archivo:
    valores = linea.strip().split(':')
    nombres = valores[0:2]
    notas = map(int, valores[2:5])
    promedio = sum(notas)/float(len(notas))
    promedio_final = int(round(promedio))
    nueva_linea = template.format(nombres[0], nombres[1], promedio_final)
    if promedio_final>=55:
        aprobados.write(nueva_linea)
    else:
        reprobados.write(nueva_linea)
archivo.close()
aprobados.close()
reprobados.close()

Ejercicio de Certamen: CR, CC, 2012-S2

[ 35 % ] Los subtítulos de una película son archivos de texto plano que tiene un formato especial para que cualquier reproductor multimedia pueda mostrarlos durante la reproducción de una película. El nombre de este tipo de archivos tiene el formato nombre_archivo.srt.

El formato que tiene este tipo de archivo es: identificación del subtítulo (como Sx, donde x es el número del subtítulo), tiempo de inicio y fin (expresado en hora:minutos:segundos,milisegundos, el texto del subtítulo, una línea en blanco y luego se repite el formato para cada subtítulo.

Observe el archivo de ejemplo los_simpsons.srt.

S1
00:00:20,000 --> 00:00:24,400
Te voy a pillar Bart

S2
00:00:24,100 --> 00:00:27,800
Maldito demonio

S3
00:00:29,100 --> 00:00:30,651
No Homero ... grrr

Los subtítulos no deberían solaparse unos con otros, es decir, el tiempo final de uno no debería ser mayor que el tiempo inicial del siguiente subtítulo. Sin embargo, esto puede ocurrir. Asuma, además, que el archivo tiene muchos subtítulos.

Ejercicio de Certamen: CR, CC, 2012-S2

(a) Escriba la función tiempo_a_tupla(tpo) que reciba un tiempo como texto y lo retorne como la tupla correspondiente.

>>> tiempo_a_tupla('00:00:20,000')
(0,0,20,0)

In [ ]:
# Solución
def tiempo_a_tupla(tpo):
    return 0
    
print tiempo_a_tupla('00:00:20,000')
print tiempo_a_tupla('10:20:30,040')
print tiempo_a_tupla('59:59:59,999')

In [30]:
# Solución
def tiempo_a_tupla(tpo):
    v = tpo.replace(",",":").split(":")
    valores_int = (int(v[0]), int(v[1]), int(v[2]), int(v[3]))
    return valores_int
    
print tiempo_a_tupla('00:00:20,000')
print tiempo_a_tupla('10:20:30,040')
print tiempo_a_tupla('59:59:59,999')


(0, 0, 20, 0)
(10, 20, 30, 40)
(59, 59, 59, 999)

In [31]:
# Solución
def tiempo_a_tupla(tpo):
    valores_str = tpo.replace(",",":").split(":")
    valores_int = map(int, valores_str)
    return tuple(valores_int)
    
print tiempo_a_tupla('00:00:20,000')
print tiempo_a_tupla('10:20:30,040')
print tiempo_a_tupla('59:59:59,999')


(0, 0, 20, 0)
(10, 20, 30, 40)
(59, 59, 59, 999)

In [32]:
# Solución
def tiempo_a_tupla(tpo):
    return tuple(map(int, tpo.replace(",",":").split(":")))
    
print tiempo_a_tupla('00:00:20,000')
print tiempo_a_tupla('10:20:30,040')
print tiempo_a_tupla('59:59:59,999')


(0, 0, 20, 0)
(10, 20, 30, 40)
(59, 59, 59, 999)

Ejercicio de Certamen: CR, CC, 2012-S2

Escriba la función solapados solapados(nombre_archivo) que reciba como parámetro el nombre del archivo de subtítulos y retorne una lista de tuplas con los subtítulos solapados. Cada tupla debe indicar los 2 subtítulos solapados.

>>> solapados('los_simpsons.srt')
[('S1', 'S2')]

(En el ejemplo hay sólo uno, pero podrían haber más)


In [ ]:
def solapados(nombre_archivo):
    archivo = open(nombre_archivo)
    lista_solapados = []
    
    for linea in archivo:
        pass
        
    archivo.close()
    return lista_solapados

solapados('data/los_simpsons.srt')
solapados('data/The.Walking.DeadS06E01.srt')

In [ ]:
def solapados(nombre_archivo):
    archivo = open(nombre_archivo)
    lista_solapados = []
    i=0
    ti_actual = (0,0,0,-1)
    tf_actual = (0,0,0,-1)
    S_actual = ""
    for linea in archivo:
        if i%4==0:
            S_anterior = S_actual
            S_actual = linea.replace("\n","").replace("\r","")
        if i%4==1:
            ti_anterior, tf_anterior = ti_actual, tf_actual
            si_actual, sf_actual = linea.split("-->")
            ti_actual = tiempo_a_tupla(si_actual)
            tf_actual = tiempo_a_tupla(sf_actual)
            if ti_actual<tf_anterior:
                lista_solapados.append((S_anterior, S_actual))
        # Incrementar i
        i += 1
    # Cerrar archivo y regresar solucion
    archivo.close()
    return lista_solapados

print solapados('data/los_simpsons.srt')
print solapados('data/The.Walking.DeadS06E01.srt')

Ejercicio de Certamen: CR, CC, 2012-S2

(c) Los subtítulos son una buena fuente para extraer los diálogos para una obra. Escriba la función transformar_dialogo(nombre_archivo) que reciba como parámetro el nombre del archivo de subtítulos y a partir de éste cree un archivo NOMBRE.dlg (con NOMBRE es el nombre del archivo antes del .srt) con los diálogos. Al principio de cada línea se deben agregar 5 guiones bajos y dos puntos _____: (ahí se supone que posteriormente se escribirá el nombre del personaje).

En nuestro caso, al ejecutar

>>> transformar_dialogo('los_simpsons.srt')

se debería generar el archivo los_simpsons.dlg:

____: Te voy a pillar Bart
____: Maldito demonio
____: No Homero ... grrr

In [ ]:
# Solucion estudiantes
def transformar_dialogo(nombre_archivo_srt):

    archivo_srt = open(nombre_archivo_srt)
    
    for linea in archivo_srt:
        pass
    
    archivo_srt.close()    
    return

transformar_dialogo('data/los_simpsons.srt')
transformar_dialogo('data/The.Walking.DeadS06E01.srt')

In [33]:
def transformar_dialogo(nombre_archivo_srt):
    nombre_archivo_dlg = nombre_archivo_srt.replace(".srt",".dlg")
    archivo_srt = open(nombre_archivo_srt)
    archivo_dlg = open(nombre_archivo_dlg, "w")
    i=0
    for linea in archivo_srt:
        if i%4==2:
            archivo_dlg.write("_"*5 + ": " +linea)
        # Incrementar i
        i += 1
    archivo_srt.close()    
    archivo_dlg.close()    
    return

transformar_dialogo('data/los_simpsons.srt')
transformar_dialogo('data/The.Walking.DeadS06E01.srt')

In [ ]:
def transformar_dialogo(nombre_archivo_srt):
    nombre_archivo_dlg = nombre_archivo_srt[:-3] + "dlg"
    archivo_srt = open(nombre_archivo_srt)
    archivo_dlg = open(nombre_archivo_dlg, "w")
    i=0
    for linea in archivo_srt:
        if i%4==2:
            archivo_dlg.write("_"*5 + ": " +linea)
        # Incrementar i
        i += 1
    archivo_srt.close()
    archivo_dlg.close()
    return

transformar_dialogo('data/los_simpsons.srt')
transformar_dialogo('data/The.Walking.DeadS06E01.srt')