Pregunta

Tengo un archivo de configuración que está en la siguiente forma:

protocol sample_thread {
    { AUTOSTART 0 }
    { BITMAP thread.gif }
    { COORDS {0 0} }
    { DATAFORMAT {
        { TYPE hl7 }
        { PREPROCS {
            { ARGS {{}} }
            { PROCS sample_proc }
        } }
    } } 
}

Es posible que el archivo real no tenga estos campos exactos, y prefiero no tener que describir la estructura de los datos es para el analizador antes de que analice.

He buscado otros analizadores de archivos de configuración, pero ninguno que he encontrado parece que puede aceptar un archivo de esta sintaxis.

Estoy buscando un módulo que pueda analizar un archivo como este, ¿alguna sugerencia?

Si alguien tiene curiosidad, el archivo en cuestión fue generado por Quovadx Cloverleaf.

¿Fue útil?

Solución

pyparsing es bastante útil para un análisis rápido y simple como este. Un mínimo sería algo así como:

import pyparsing
string = pyparsing.CharsNotIn("{} \t\r\n")
group = pyparsing.Forward()
group << pyparsing.Group(pyparsing.Literal("{").suppress() + 
                         pyparsing.ZeroOrMore(group) + 
                         pyparsing.Literal("}").suppress()) 
        | string

toplevel = pyparsing.OneOrMore(group)

Lo usa como:

>>> toplevel.parseString(text)
['protocol', 'sample_thread', [['AUTOSTART', '0'], ['BITMAP', 'thread.gif'], 
['COORDS', ['0', '0']], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', 
[['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]]

A partir de ahí, puede ser más sofisticado como desee (los números de análisis por separado de las cuerdas, buscar nombres de campo específicos, etc.). Lo anterior es bastante general, solo busca cadenas (definidas como cualquier carácter no Whitespace, excepto "{" y "}") y {} listas delimitadas de cadenas.

Otros consejos

Tomando la solución de PyParsing de Brian en otro paso, puede crear un cuasi-deseserializador para este formato utilizando la clase DICT:

import pyparsing

string = pyparsing.CharsNotIn("{} \t\r\n")
# use Word instead of CharsNotIn, to do whitespace skipping
stringchars = pyparsing.printables.replace("{","").replace("}","")
string = pyparsing.Word( stringchars )
# define a simple integer, plus auto-converting parse action
integer = pyparsing.Word("0123456789").setParseAction(lambda t : int(t[0]))
group = pyparsing.Forward()
group << ( pyparsing.Group(pyparsing.Literal("{").suppress() +
    pyparsing.ZeroOrMore(group) +
    pyparsing.Literal("}").suppress())
    | integer | string )

toplevel = pyparsing.OneOrMore(group)

sample = """
protocol sample_thread {
    { AUTOSTART 0 }
    { BITMAP thread.gif }
    { COORDS {0 0} }
    { DATAFORMAT {
        { TYPE hl7 }
        { PREPROCS {
            { ARGS {{}} }
            { PROCS sample_proc }
        } }
    } } 
    }
"""

print toplevel.parseString(sample).asList()

# Now define something a little more meaningful for a protocol structure, 
# and use Dict to auto-assign results names
LBRACE,RBRACE = map(pyparsing.Suppress,"{}")
protocol = ( pyparsing.Keyword("protocol") + 
             string("name") + 
             LBRACE + 
             pyparsing.Dict(pyparsing.OneOrMore(
                pyparsing.Group(LBRACE + string + group + RBRACE)
                ) )("parameters") + 
             RBRACE )

results = protocol.parseString(sample)
print results.name
print results.parameters.BITMAP
print results.parameters.keys()
print results.dump()

Huellas dactilares

['protocol', 'sample_thread', [['AUTOSTART', 0], ['BITMAP', 'thread.gif'], ['COORDS', 

[0, 0]], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]]
sample_thread
thread.gif
['DATAFORMAT', 'COORDS', 'AUTOSTART', 'BITMAP']
['protocol', 'sample_thread', [['AUTOSTART', 0], ['BITMAP', 'thread.gif'], ['COORDS', [0, 0]], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]]
- name: sample_thread
- parameters: [['AUTOSTART', 0], ['BITMAP', 'thread.gif'], ['COORDS', [0, 0]], ['DATAFORMAT', [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]]]
  - AUTOSTART: 0
  - BITMAP: thread.gif
  - COORDS: [0, 0]
  - DATAFORMAT: [['TYPE', 'hl7'], ['PREPROCS', [['ARGS', [[]]], ['PROCS', 'sample_proc']]]]

Creo que obtendrás más rápido con PyParsing.

-- Pablo

Intentaré responder lo que creo que es la (s) pregunta (s) que falta ...

Los archivos de configuración vienen en muchos formatos. Hay formatos bien conocidos como la configuración *.ini o Apache: estos tienden a tener muchos analizadores disponibles.

Luego hay formatos personalizados. Eso es lo que el tuyo parece ser (podría ser un formato bien definido que tú y yo nunca antes había visto, pero hasta que sepas qué es eso realmente no importa).

Comenzaría con el software del que proviene y vería si tienen una API de programación que puede cargar/producir estos archivos. Si nada es obvio, llame a Quovadx. Lo más probable es que alguien ya haya resuelto este problema.

De lo contrario, probablemente esté solo para crear su propio analizador.

Escribir un analizador para este formato no sería terriblemente difícil suponiendo que su muestra sea representativa de un ejemplo completo. Es una jerarquía de valores donde cada nodo puede contener un valor o una jerarquía infantil de valores. Una vez que haya definido los tipos básicos, los valores pueden contener el analizador es una estructura muy simple.

Puede escribir esto razonablemente rápidamente usando algo como Lex/Flex o simplemente un analizador directo en el lenguaje de su elección.

Puede escribir fácilmente un script en Python que lo convertirá en Python Dict, el formato se parece casi a pares de valor de nombre jerárquicos, solo el problema parece ser Coards {0 0}, donde {0 0} no es un par de valores de nombre, sino que, sino que, sino que, sino que, sino que, sino que, pero no es un par de valores de nombre, sino que, pero, sino que, pero no es un par de valores, sino Una lista, entonces, ¿quién sabe qué otros casos están en formato? Creo que su mejor opción es tener especificaciones para ese formato y escribir un script de Python simple para leerlo.

Su archivo de configuración es muy similar a Json (más o menos, reemplace todos sus "{" y "}" con [" y "]). La mayoría de los idiomas tienen un analizador JSON incorporado (PHP, Ruby, Python, etc.), y si no, hay bibliotecas disponibles para manejarlo por usted.

Si no puede cambiar el formato del archivo de configuración, puede leer todo el contenido del archivo como una cadena y reemplazar todos los caracteres "{" y "}" a través de cualquier medio que prefiera. Luego puedes analizar la cadena como JSON, y estás configurado.

Busqué un poco en el Tienda de quesos, pero no encontré nada útil para su ejemplo. Comprobar el Ejemplos página y este analizador específico (su sintaxis se asemeja un poco a la tuya). Creo que esto debería ayudarte a escribir el tuyo.

Examinar Lex y yacc. Un poco de curva de aprendizaje, pero pueden generar analizadores para cualquier idioma.

¿Tal vez podría escribir un script simple que convertirá su configuración en archivo XML y luego lo lea solo usando LXML, sopa beatuosa o cualquier otra cosa? Y su convertidor podría usar PyParsing o expresiones regulares, por ejemplo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top