txt - leer columnas en python
Procesamiento repetido de archivos de texto estructurados con python (3)
Tengo un gran archivo de texto estructurado en bloques como:
Student = {
PInfo = {
ID = 0001;
Name.First = "Joe";
Name.Last = "Burger";
DOB = "01/01/2000";
};
School = "West High";
Address = {
Str1 = "001 Main St.";
Zip = 12345;
};
};
Student = {
PInfo = {
ID = 0002;
Name.First = "John";
Name.Last = "Smith";
DOB = "02/02/2002";
};
School = "East High";
Address = {
Str1 = "001 40nd St.";
Zip = 12346;
};
Club = "Football";
};
....
Los bloques de Estudiantes comparten las mismas entradas como "PInfo", "Escuela" y "Dirección", pero algunos de ellos pueden tener entradas adicionales, como la información "Club" para "John Smith" que no está incluida para "Joe Burger" . Lo que quiero hacer es obtener el nombre, el nombre de la escuela y el código postal de cada estudiante y almacenarlos en un diccionario, como
{''Joe Burger'':{School:''West High'', Zip:12345}, ''John Smith'':{School:''East High'', Zip:12346}, ...}
Siendo nuevo en la programación de Python, traté de abrir el archivo y analizarlo línea por línea, pero parece tan engorroso. Y el archivo real es bastante grande y más complicado que el ejemplo que publiqué anteriormente. Me pregunto si hay una manera más fácil de hacerlo. Gracias por delante
no es json, sino similar estructurado. deberías poder reformatearlo en json.
- "=" -> ":"
- cita todas las teclas con '''' ''''
- ";" -> ","
- eliminar todos "," que son seguidos por un "}"
- ponerlo en llaves
- analizarlo con json.loads
Para analizar el archivo, puede definir una gramática que describa su formato de entrada y usarlo para generar un analizador.
Hay muchos analizadores de lenguaje en Python . Por ejemplo, podría usar Grako que toma gramáticas en una variación de EBNF como entrada, y salidas memorando analizadores PEG en Python.
Para instalar Grako, ejecuta pip install grako
.
Aquí hay gramática para su formato usando el sabor de la sintaxis EBNF de Grako:
(* a file is zero or more records *)
file = { record }* $;
record = name ''='' value '';'' ;
name = /[A-Z][a-zA-Z0-9.]*/ ;
value = object | integer | string ;
(* an object contains one or more records *)
object = ''{'' { record }+ ''}'' ;
integer = /[0-9]+/ ;
string = ''"'' /[^"]*/ ''"'';
Para generar el analizador, guarde la gramática en un archivo, por ejemplo, Structured.ebnf
y ejecute:
$ grako -o structured_parser.py Structured.ebnf
Crea el módulo structured_parser
que se puede usar para extraer la información del alumno de la entrada:
#!/usr/bin/env python
from structured_parser import StructuredParser
class Semantics(object):
def record(self, ast):
# record = name ''='' value '';'' ;
# value = object | integer | string ;
return ast[0], ast[2] # name, value
def object(self, ast):
# object = ''{'' { record }+ ''}'' ;
return dict(ast[1])
def integer(self, ast):
# integer = /[0-9]+/ ;
return int(ast)
def string(self, ast):
# string = ''"'' /[^"]*/ ''"'';
return ast[1]
with open(''input.txt'') as file:
text = file.read()
parser = StructuredParser()
ast = parser.parse(text, rule_name=''file'', semantics=Semantics())
students = [value for name, value in ast if name == ''Student'']
d = {''{0[Name.First]} {0[Name.Last]}''.format(s[''PInfo'']):
dict(School=s[''School''], Zip=s[''Address''][''Zip''])
for s in students}
from pprint import pprint
pprint(d)
Salida
{''Joe Burger'': {''School'': u''West High'', ''Zip'': 12345},
''John Smith'': {''School'': u''East High'', ''Zip'': 12346}}
Para tal cosa, uso Marpa :: R2 , una interfaz Perl para Marpa, un analizador BNF general . Permite describir el texto como reglas gramaticales y analizarlas en un árbol de matrices (árbol de análisis sintáctico). A continuación, puede recorrer el árbol para guardar los resultados como un hash de hashes (hash es perl para el diccionario de python) o usarlo como está.
Preparé un ejemplo de trabajo usando su entrada: analizador , árbol de resultados .
Espero que esto ayude.
PS Ejemplo de ast_traverse()
: valores de análisis de un bloque de texto basado en claves específicas