Tengo un archivo de texto que tiene datos en la siguiente forma:

{"id": 1, {"device_data": 123}, "created_at": "2020-04-03"}{"id": 2, {"device_data": 123}, "created_at": '2020-04-03'}{"id": 2, {"device_data": 123}, "created_at": "2020-04-03"}{"id": 2, {"device_data": 123}, "created_at": '2020-04-03'}

No hay delimitadores \n o delimitadores , que pueda usar aquí. Me gustaría analizar esto en una lista de diccionarios para cargar los datos en un marco de datos.

He intentado analizar esto usando .split() y listar la comprensión haciendo algo como esto:

lst = [x + '}' for x in data.split('}') if x != '']

Pero esto obviamente se rompe para los registros que tienen objetos anidados.

También intenté hacer esto con expresiones regulares, pero estoy luchando por descubrir la forma adecuada. Esto es lo que tengo hasta ahora:

re.split('(\{(.*)\})', data) 

Según las sugerencias a continuación, también intenté usar la biblioteca json.

with open('path/to/file', 'r') as f:
    res = json.load(f)

Sin embargo, esto provocó un error con el siguiente mensaje: JSONDecodeError: Extra data. Creo que esto se debe al hecho de que hay varios json válidos en este archivo.

Quería usar el comando json.load() con un bucle for, pero luego tuve problemas para descubrir cómo dividir adecuadamente el contenido del archivo.

¿Alguien tiene una sugerencia sobre cómo abordar este tipo de problema?

0
genhernandez 30 may. 2020 a las 01:29

3 respuestas

La mejor respuesta

Su separador de registros es:

}{

Tan dado

txt="{'id': 1, {'device_data': 123}, 'created_at': '2020-04-03'}{'id': 2, {'device_data': 123}, 'created_at': '2020-04-03'}{'id': 2, {'device_data': 123}, 'created_at': '2020-04-03'}{'id': 2, {'device_data': 123}, 'created_at': '2020-04-03'}"

Dividido en registros con:

records=txt.split('}{')

Los resultados se ven así:

records[0]="{'id': 1, {'device_data': 123}, 'created_at': '2020-04-03'"
records[1]="'id': 2, {'device_data': 123}, 'created_at': '2020-04-03'"

Y analizar los registros en el diccionario con

mydictlist = []
for record in records:
    # clean up excess brackets and tokens
    record = record.replace('{','').replace('}','').replace("'",'')
    mydict = dict((k.strip(), v.strip()) for k,v in
          (item.split(':') for item in record.split(',')))
    mydictlist.append(mydict)

El resultado del ejemplo se ve así:

mydictlist[2] = {'id': '2', 'device_data': '123', 'created_at': '2020-04-03'}
1
Paul Smith 29 may. 2020 a las 23:41

Sus datos se parecen a JSON, pero con comillas simples en lugar de dobles.

Si ese es el caso, primero sugeriría cambiar sus datos (si es posible) para usar solo json válidos, y luego puede hacer fácilmente:

myfile.json :

{ "foo": 42 }
import json

with open('myfile.json') as f:
  obj = json.load(f)

print(obj) # {'foo': 42}

Entonces obj es un diccionario válido de Python que puede usar normalmente.

Si no puede utilizar JSON con comillas dobles, puede consultar esta pregunta sobre el análisis de JSON con comillas simples.

1
MHebes 29 may. 2020 a las 22:53

Regex no maneja formatos anidados como este de manera efectiva.

Esto se parece un poco a JSON, y Python tiene el paquete integrado json, lo que podría ayudar. Para usarlo en estos datos, primero deberá convertir las comillas simples en comillas dobles: data_string.replace("'", '"'). Pero el formato probablemente todavía sea lo suficientemente diferente de JSON como para ser un problema.

Si sabe qué generó los datos, eso puede ayudarlo a descubrir qué analizará los datos. De lo contrario, esta respuesta explica cómo analizar manualmente las expresiones anidadas.

1
dolay 29 may. 2020 a las 23:17