una txt texto sobrescribir por lineas linea leer las guardar especifica escribir delimitado datos contar como comas archivos archivo agregar c# fileparse

txt - ¿El mejor método de análisis de archivos de texto en C#?



leer y escribir archivos en c# (8)

Quiero analizar una cosa de archivo de configuración, así:

[KEY:Value] [SUBKEY:SubValue]

Ahora comencé con un StreamReader , convirtiendo líneas en arreglos de caracteres, cuando pensé que debía haber una mejor manera. Entonces, te pido, humilde lector, que me ayudes.

Una restricción es que tiene que funcionar en un entorno Linux / Mono (1.2.6 para ser exactos). No tengo la última versión 2.0 (de Mono), así que trate de restringir las características del lenguaje a C # 2.0 o C # 1.0.


Lo consideré, pero no voy a usar XML. Voy a escribir esto a mano, y editar manualmente XML hace que me duela el cerebro. : '')

¿Has mirado a YAML ?

Obtiene los beneficios de XML sin todo el dolor y el sufrimiento. Se usa ampliamente en la comunidad de ruby ​​para cosas como archivos de configuración, datos de bases de datos pre-preparados, etc.

aquí hay un ejemplo

customer: name: Orion age: 26 addresses: - type: Work number: 12 street: Bob Street - type: Home number: 15 street: Secret Road

Parece que hay una biblioteca C # aquí , que no he usado personalmente, pero yaml es bastante simple, así que "¿qué tan difícil puede ser?" :-)

Yo diría que es preferible inventar su propio formato ad-hoc (y tratar con errores del analizador sintáctico)


Estuve mirando casi este mismo problema el otro día: este artículo sobre tokenización de cadenas es exactamente lo que necesita. Deberá definir sus tokens como algo como:

@"(?&ltlevel>/s) | " + @"(?&ltterm>[^:/s]) | " + @"(?&ltseparator>:)"

El artículo hace un buen trabajo al explicarlo. A partir de ahí, simplemente comienzas a comer tokens como mejor te parezca.

Protip: para un analizador LL (1) (léase: fácil), los tokens no pueden compartir un prefijo. Si tienes abc como token, no puedes tener ace como token

Nota: falta el artículo | personajes en sus ejemplos, simplemente tírelos.


Me parece que sería mejor usar un archivo de configuración basado en XML, ya que ya hay clases .NET que pueden leer y almacenar la información de manera relativamente fácil. ¿Hay alguna razón por la cual esto no es posible?

@Bernardo: Es cierto que la edición manual de XML es tediosa, pero la estructura que usted presenta ya se parece mucho a XML.

Entonces sí, tiene un buen método allí.


También puede usar una pila y usar un algoritmo push / pop. Éste coincide con las etiquetas de apertura / cierre.

public string check() { ArrayList tags = getTags(); int stackSize = tags.Count; Stack stack = new Stack(stackSize); foreach (string tag in tags) { if (!tag.Contains(''/'')) { stack.push(tag); } else { if (!stack.isEmpty()) { string startTag = stack.pop(); startTag = startTag.Substring(1, startTag.Length - 1); string endTag = tag.Substring(2, tag.Length - 2); if (!startTag.Equals(endTag)) { return "Fout: geen matchende eindtag"; } } else { return "Fout: geen matchende openeningstag"; } } } if (!stack.isEmpty()) { return "Fout: geen matchende eindtag"; } return "Xml is valid"; }

Probablemente pueda adaptarse para que pueda leer el contenido de su archivo. Las expresiones regulares también son una buena idea.


@Gishu

En realidad, una vez que me había acomodado para los personajes escapados, mi expresión regular corría un poco más lento que mi analizador recursivo escrito arriba y sin anidamiento (vinculando subelementos a sus padres) y el informe de errores del analizador escrito a mano.

La expresión regular fue un poco más rápida de escribir (aunque tengo un poco de experiencia con analizadores de mano) pero eso es sin buenos informes de errores. Una vez que agrega que se vuelve un poco más difícil y más largo de hacer.

También encuentro que el analizador escrito a mano es más fácil de entender la intención de. Por ejemplo, aquí está el fragmento de código:

private static Node ParseNode(TextReader reader) { Node node = new Node(); int indentation = ParseWhitespace(reader); Expect(reader, ''[''); node.Key = ParseTerminatedString(reader, '':''); node.Value = ParseTerminatedString(reader, '']''); }


Independientemente del formato que persista, usar una Regex sería la forma más rápida de analizar. En ruby ​​probablemente serían unas pocas líneas de código.

/[KEY:(.*)/] /[SUBKEY:(.*)/]

Estos dos obtendrán el Valor y SubValor en el primer grupo. Consulte MSDN sobre cómo hacer coincidir una expresión regular con una cadena.

Esto es algo que todos deberían tener en su gatito. Los días previos a Regex parecerían la Era de Hielo.


Hay otra biblioteca YAML para .NET que está en desarrollo. En este momento es compatible con la lectura de secuencias YAML y ha sido probado en Windows y Mono. El soporte de escritura se está implementando actualmente.


El uso de una biblioteca casi siempre es preferible hacer su propio. Aquí hay una lista rápida de "Oh, nunca necesitaré eso / no pensé en eso" puntos que terminarán por morderte más adelante:

  • Escapando personajes ¿Qué sucede si quiere a: en la clave o] en el valor?
  • Escapar del personaje de escape.
  • Unicode
  • Mezcla de pestañas y espacios (ver los problemas con la sintaxis sensible al espacio en blanco de Python)
  • Manejo de diferentes formatos de devolución de caracteres
  • Manejo de informes de errores de sintaxis

Como otros han sugerido, YAML parece ser su mejor apuesta.