sirve qué que programación para nucleo notación medicina mecanica indentado indentada indentación codigo python parsing data-structures dictionary nested

python - qué - que es la indentación de codigo y para que sirve



Crear un árbol/dict profundamente anidado de un archivo de texto sangrado en python (3)

Básicamente, quiero iterar a través de un archivo y poner el contenido de cada línea en un dictado profundamente anidado, cuya estructura se define por la cantidad de espacios en blanco al comienzo de cada línea.

Esencialmente, el objetivo es tomar algo como esto:

a b c d e

Y conviértalo en algo como esto:

{"a":{"b":"c","d":"e"}}

O esto:

apple colours red yellow green type granny smith price 0.10

dentro de esto:

{"apple":{"colours":["red","yellow","green"],"type":"granny smith","price":0.10}

Para poder enviarlo al módulo JSON de Python y hacer algunos JSON.

Por el momento estoy tratando de hacer un dict y una lista en pasos como este:

  1. {"a":""} ["a"]
  2. {"a":"b"} ["a"]
  3. {"a":{"b":"c"}} ["a","b"]
  4. {"a":{"b":{"c":"d"}}}} ["a","b","c"]
  5. {"a":{"b":{"c":"d"},"e":""}} ["a","e"]
  6. {"a":{"b":{"c":"d"},"e":"f"}} ["a","e"]
  7. {"a":{"b":{"c":"d"},"e":{"f":"g"}}} ["a","e","f"]

etc.

La lista actúa como "migas de pan" que muestra dónde colgué por última vez un dict.

Para hacer esto, necesito una manera de recorrer la lista y generar algo como dict["a"]["e"]["f"] para llegar a esa última frase. He echado un vistazo a la clase AutoVivification que alguien ha hecho y que parece muy útil, pero de lo que no estoy seguro es:

  1. Si estoy usando la estructura de datos correcta para esto (estoy planeando enviarlo a la biblioteca JSON para crear un objeto JSON)
  2. Cómo usar AutoVivification en esta instancia
  3. Si hay una mejor manera en general para abordar este problema.

Se me ocurrió la siguiente función pero no funciona:

def get_nested(dict,array,i): if i != None: i += 1 if array[i] in dict: return get_nested(dict[array[i]],array) else: return dict else: i = 0 return get_nested(dict[array[i]],array)

Agradecería ayuda!

(El resto de mi código extremadamente incompleto está aquí :)

#Import relevant libraries import codecs import sys #Functions def stripped(str): if tab_spaced: return str.lstrip(''/t'').rstrip(''/n/r'') else: return str.lstrip().rstrip(''/n/r'') def current_ws(): if whitespacing == 0 or not tab_spaced: return len(line) - len(line.lstrip()) if tab_spaced: return len(line) - len(line.lstrip(''/t/n/r'')) def get_nested(adict,anarray,i): if i != None: i += 1 if anarray[i] in adict: return get_nested(adict[anarray[i]],anarray) else: return adict else: i = 0 return get_nested(adict[anarray[i]],anarray) #initialise variables jsondict = {} unclosed_tags = [] debug = [] vividfilename = ''simple.vivid'' # vividfilename = sys.argv[1] if len(sys.argv)>2: jsfilename = sys.argv[2] else: jsfilename = vividfilename.split(''.'')[0] + ''.json'' whitespacing = 0 whitespace_array = [0,0] tab_spaced = False #open the file with codecs.open(vividfilename,''rU'', "utf-8-sig") as vividfile: for line in vividfile: #work out how many whitespaces at start whitespace_array.append(current_ws()) #For first line with whitespace, work out the whitespacing (eg tab vs 4-space) if whitespacing == 0 and whitespace_array[-1] > 0: whitespacing = whitespace_array[-1] if line[0] == ''/t'': tab_spaced = True #strip out whitespace at start and end stripped_line = stripped(line) if whitespace_array[-1] == 0: jsondict[stripped_line] = "" unclosed_tags.append(stripped_line) if whitespace_array[-2] < whitespace_array[-1]: oldnested = get_nested(jsondict,whitespace_array,None) print oldnested # jsondict.pop(unclosed_tags[-1]) # jsondict[unclosed_tags[-1]]={stripped_line:""} # unclosed_tags.append(stripped_line) print jsondict print unclosed_tags print jsondict print unclosed_tags


Antes que nada, no uses array y dict como nombres de variables porque son palabras reservadas en Python y reutilizarlas puede terminar en todo tipo de caos.

De acuerdo, entonces si te encuentro correctamente, tienes un árbol en un archivo de texto, con la paternidad indicada por indentaciones, y quieres recuperar la estructura de árbol real. ¿Derecha?

¿El siguiente parece un bosquejo válido? Porque tengo problemas para poner tu código actual en contexto.

result = {} last_indentation = 0 for l in f.xreadlines(): (c, i) = parse(l) # create parse to return character and indentation if i==last_indentation: # sibling to last elif i>last_indentation: # child to last else: # end of children, back to a higher level

OK, entonces tu lista son los padres actuales, eso es correcto, pero los mantendré apuntando al diccionario que has creado, no a la letra literal

acaba de comenzar algunas cosas aquí

result = {} parents = {} last_indentation = 1 # start with 1 so 0 is the root of tree parents[0] = result for l in f.xreadlines(): (c, i) = parse(l) # create parse to return character and indentation if i==last_indentation: new_el = {} parents[i-1][c] = new_el parents[i] = new_el elif i>last_indentation: # child to last else: # end of children, back to a higher level


El siguiente código tomará un archivo con sangría de bloque y se convertirá en un árbol XML; esta:

foo bar baz ban bal

... se convierte en:

<cmd>foo</cmd> <cmd>bar</cmd> <block> <name>baz</name> <cmd>ban</cmd> <cmd>bal</cmd> </block>

La técnica básica es:

  1. Establecer sangría a 0
  2. Para cada línea, obtenga la sangría
  3. Si> actual, baje y guarde el bloque / ident actual en una pila
  4. Si == actual, anexa al bloque actual
  5. Si <actual, sal de la pila hasta que llegues a la sangría correspondiente

Asi que:

from lxml import builder C = builder.ElementMaker() def indent(line): strip = line.lstrip() return len(line) - len(strip), strip def parse_blockcfg(data): top = current_block = C.config() stack = [] current_indent = 0 lines = data.split(''/n'') while lines: line = lines.pop(0) i, line = indent(line) if i==current_indent: pass elif i > current_indent: # we''ve gone down a level, convert the <cmd> to a block # and then save the current ident and block to the stack prev.tag = ''block'' prev.append(C.name(prev.text)) prev.text = None stack.insert(0, (current_indent, current_block)) current_indent = i current_block = prev elif i < current_indent: # we''ve gone up one or more levels, pop the stack # until we find out which level and return to it found = False while stack: parent_indent, parent_block = stack.pop(0) if parent_indent==i: found = True break if not found: raise Exception(''indent not found in parent stack'') current_indent = i current_block = parent_block prev = C.cmd(line) current_block.append(prev) return top


Aquí hay una solución recursiva. Primero, transforma la entrada de la siguiente manera.

Entrada:

person: address: street1: 123 Bar St street2: city: Madison state: WI zip: 55555 web: email: [email protected]

Resultado del primer paso:

[{''name'':''person'',''value'':'''',''level'':0}, {''name'':''address'',''value'':'''',''level'':1}, {''name'':''street1'',''value'':''123 Bar St'',''level'':2}, {''name'':''street2'',''value'':'''',''level'':2}, {''name'':''city'',''value'':''Madison'',''level'':2}, {''name'':''state'',''value'':''WI'',''level'':2}, {''name'':''zip'',''value'':55555,''level'':2}, {''name'':''web'',''value'':'''',''level'':1}, {''name'':''email'',''value'':''[email protected]'',''level'':2}]

Esto es fácil de lograr con la split('':'') y contando el número de pestañas iniciales:

def tab_level(astr): """Count number of leading tabs in a string """ return len(astr)- len(astr.lstrip(''/t''))

Luego, alimente la salida del primer paso a la siguiente función:

def ttree_to_json(ttree,level=0): result = {} for i in range(0,len(ttree)): cn = ttree[i] try: nn = ttree[i+1] except: nn = {''level'':-1} # Edge cases if cn[''level'']>level: continue if cn[''level'']<level: return result # Recursion if nn[''level'']==level: dict_insert_or_append(result,cn[''name''],cn[''value'']) elif nn[''level'']>level: rr = ttree_to_json(ttree[i+1:], level=nn[''level'']) dict_insert_or_append(result,cn[''name''],rr) else: dict_insert_or_append(result,cn[''name''],cn[''value'']) return result return result

dónde:

def dict_insert_or_append(adict,key,val): """Insert a value in dict at key if one does not exist Otherwise, convert value to list and append """ if key in adict: if type(adict[key]) != list: adict[key] = [adict[key]] adict[key].append(val) else: adict[key] = val