De txt a diccionario

Iniciado por SlayerBur, 30 Mayo 2021, 20:12 PM

0 Miembros y 1 Visitante están viendo este tema.

SlayerBur

Buen día.

Quería saber si alguien sabría como hacer para que el contenido de un txt (guardado previamente con la informacion de un diccionario), luego pueda cargarlo, volver a modificarlo y guardarlo nuevamente.
El guardado funciona correctamente, el problema sucede cuando cargo el texto, una vez cargado, todo lo que utilizaba el diccionario comienza a fallar.

Guardado:

   file = open("./filename.txt", "w")
   for key, value in datos.items():
       file.write(str(key)+ ": " + str(value))
   file.close()




   file = open("./filename.txt", "r")
   for linea in file.readlines():
       #l = linea.replace("'"," ").replace("[","").replace("]","").replace(",","")
       datos = str({linea})


Gracias de antemano

DtxdF

Hola @SlayerBur

La cuestión es que estás abriendo el archivo en modo escritura (w), pero este modo borrará todo el contenido que tenga el archivo de destino, por lo que si haces una lectura mucho después, verás que estará vacío.

Puedes hacer dos cosas. La primera es abrir y leer todo el archivo primero, pero ésto consume mucha memoria, por lo que sería útil sólo si no te importa desperciarla y también si es menos de la que está en uso. La segunda es leer línea por línea, modificarla y escribir o en la salida o en un archivo de salida diferente al que está abierto.

Recomiendo la segunda para la mayoría de casos. Incluso con la segunda opción, en caso de enviar el resultado en la salida, puedes combinar ese contenido con otros programas al estilo unix usando tuberías.

~ DtxdF

SlayerBur

Cita de: DtxdF en 30 Mayo 2021, 23:56 PM
Hola @SlayerBur

La cuestión es que estás abriendo el archivo en modo escritura (w), pero este modo borrará todo el contenido que tenga el archivo de destino, por lo que si haces una lectura mucho después, verás que estará vacío.

Puedes hacer dos cosas. La primera es abrir y leer todo el archivo primero, pero ésto consume mucha memoria, por lo que sería útil sólo si no te importa desperciarla y también si es menos de la que está en uso. La segunda es leer línea por línea, modificarla y escribir o en la salida o en un archivo de salida diferente al que está abierto.

Recomiendo la segunda para la mayoría de casos. Incluso con la segunda opción, en caso de enviar el resultado en la salida, puedes combinar ese contenido con otros programas al estilo unix usando tuberías.

~ DtxdF

El problema no es el guardado, la idea es que remplace todo el contenido.
el problema es al cargar, que no se crea el diccionario.
la informacion se guarda asi:

Imagen: ['.png', '.NEF', '.jpg', '.JPG', '.ao']Texto: ['.doc', '.pdf', '.cfg']Videos: ['.mp4', '.avi', '.flv']Otros: []

lo que quiero es que esa informacion del .txt pase a ser un diccionario asi:

datos = {"Imagen":[".png",".NEF",".jpg", ".JPG"], "Texto":[".doc",".pdf",".cfg"], "Videos":[".mp4",".avi",".flv"], "Otros":[]}

DtxdF

Código (python) [Seleccionar]
#!/usr/local/bin/python3.7

import re
import pprint

filename = "filename.txt"
files = {}

with open(filename, "r") as fd:
    for line in fd:
        line = line.strip()
        if not (line):
            continue

        tokens = re.split("(\w+: )+", line)
        i = 0
        while (i < len(tokens)-1):
            name = tokens[i].strip()
            if not name:
                i += 1
                continue

            extensions = tokens[i+1].strip()
           
            files[name] = re.sub("(\[|\])", "", extensions)
            files[name] = [x.strip() for x in files[name].split(",")]

            i += 2

pprint.pprint(files)


Resultado:
{'Imagen:': ["'.png'", "'.NEF'", "'.jpg'", "'.JPG'", "'.ao'"],
'Otros:': [''],
'Texto:': ["'.doc'", "'.pdf'", "'.cfg'"],
'Videos:': ["'.mp4'", "'.avi'", "'.flv'"]}


Faltaría eliminar las comillas simples, pero ya eso es más fácil, o simplemente no puedes incluirlo en filename.txt.

Espero te sirva.

~ DtxdF

tincopasan

partamos de la base que la sintaxis visible del guardado es un asco,no hay comas para separa los items o salto de línea en el .txt

hay muchas formas de hacerlo:

Código (python) [Seleccionar]
#-*- coding: utf -8 -*-
with open("filename.txt", ) as archivo:
    cadena = archivo.read()

cadena=cadena.replace(']',']*').split('*')
datos = {}
for x in range(len(cadena)-1):
    temp = cadena[x].split(':')
    datos[temp[0]]= eval(temp[1])


y todo eso se podría evitar si guardas los datos como diccionario correctamente.

SlayerBur

Cita de: DtxdF en 31 Mayo 2021, 00:34 AM
Código (python) [Seleccionar]
#!/usr/local/bin/python3.7

import re
import pprint

filename = "filename.txt"
files = {}

with open(filename, "r") as fd:
    for line in fd:
        line = line.strip()
        if not (line):
            continue

        tokens = re.split("(\w+: )+", line)
        i = 0
        while (i < len(tokens)-1):
            name = tokens[i].strip()
            if not name:
                i += 1
                continue

            extensions = tokens[i+1].strip()
           
            files[name] = re.sub("(\[|\])", "", extensions)
            files[name] = [x.strip() for x in files[name].split(",")]

            i += 2

pprint.pprint(files)


Resultado:
{'Imagen:': ["'.png'", "'.NEF'", "'.jpg'", "'.JPG'", "'.ao'"],
'Otros:': [''],
'Texto:': ["'.doc'", "'.pdf'", "'.cfg'"],
'Videos:': ["'.mp4'", "'.avi'", "'.flv'"]}


Faltaría eliminar las comillas simples, pero ya eso es más fácil, o simplemente no puedes incluirlo en filename.txt.

Espero te sirva.

~ DtxdF

Tuve que hacer una pequeña modificacion pero ya quedo, gracias :D 

DtxdF

#6
Cita de: tincopasan en 31 Mayo 2021, 01:43 AM
partamos de la base que la sintaxis visible del guardado es un asco,no hay comas para separa los items o salto de línea en el .txt

hay muchas formas de hacerlo:

Código (python) [Seleccionar]
#-*- coding: utf -8 -*-
with open("filename.txt", ) as archivo:
   cadena = archivo.read()

cadena=cadena.replace(']',']*').split('*')
datos = {}
for x in range(len(cadena)-1):
   temp = cadena[x].split(':')
   datos[temp[0]]= eval(temp[1])


y todo eso se podría evitar si guardas los datos como diccionario correctamente.

El problema con eval(...) es que ejecuta código arbitrario. Por ejemplo:

CitarImagen: ['.png', '.NEF', '.jpg', '.JPG', '.ao']Texto: ['.doc', '.pdf', '.cfg']Videos: ['.mp4', '.avi', '.flv']Otros: [__import__("os").system("whoami")]

La saldría sería:

Código (bash) [Seleccionar]
dtxdf

@SlayerBur

Sí, me había faltado agregar un pequeño trozo. Línea 26:

Código (python) [Seleccionar]
files[name] = [x.strip().replace("'", "") for x in files[name].split(",")]

El replace(...).

Editado:

Por cierto, y siguiendo la recomendación de @tincopasan, es recomendable colocar nuevas líneas para que sea más fácil editarlo. Por suerte el script puede leer e interpretar de la misma manera lo siguiente:

Con nuevas líneas:
Imagen: ['.png', '.NEF', '.jpg', '.JPG', '.ao']
Texto: ['.doc', '.pdf', '.cfg']
Videos: ['.mp4', '.avi', '.flv']
Otros: []


Sin nuevas líneas:
Imagen: ['.png', '.NEF', '.jpg', '.JPG', '.ao']Texto: ['.doc', '.pdf', '.cfg']Videos: ['.mp4', '.avi', '.flv']Otros: []

La saldría sería la misma, y es más recomendable la primera opción para el que tiene que editar las extensiones.

~ DtxdF

tincopasan

DtxdF bueno supongamos que los archivos no son creados por él, sino sería muy tonto poner "código malicioso" se usal literal_eval de la biblioteca ast y listo, siguen siendo muchas menos líneas de código y bibliotecas para analizar el texto, etc.

SlayerBur

Cita de: DtxdF en  1 Junio 2021, 02:10 AM
El problema con eval(...) es que ejecuta código arbitrario. Por ejemplo:

La saldría sería:

Código (bash) [Seleccionar]
dtxdf

@SlayerBur

Sí, me había faltado agregar un pequeño trozo. Línea 26:

Código (python) [Seleccionar]
files[name] = [x.strip().replace("'", "") for x in files[name].split(",")]

El replace(...).

Editado:

Por cierto, y siguiendo la recomendación de @tincopasan, es recomendable colocar nuevas líneas para que sea más fácil editarlo. Por suerte el script puede leer e interpretar de la misma manera lo siguiente:

Con nuevas líneas:
Imagen: ['.png', '.NEF', '.jpg', '.JPG', '.ao']
Texto: ['.doc', '.pdf', '.cfg']
Videos: ['.mp4', '.avi', '.flv']
Otros: []


Sin nuevas líneas:
Imagen: ['.png', '.NEF', '.jpg', '.JPG', '.ao']Texto: ['.doc', '.pdf', '.cfg']Videos: ['.mp4', '.avi', '.flv']Otros: []

La saldría sería la misma, y es más recomendable la primera opción para el que tiene que editar las extensiones.

~ DtxdF

El codigo es creado mediante una inteface grafica, no seria necesario usar el txt.
Inclusive estoy pensando en publicar el codigo, para el que quiera usarle o modificarle :D