2009-05-13 15 views
22

Al formatear texto, quise decir algo más complicado.Cómo analizar un archivo de texto con C#

Al principio comencé a agregar manualmente las 5000 líneas del archivo de texto que estoy haciendo esta pregunta para mi proyecto.

El archivo de texto tiene 5000 líneas con diferente length.For ejemplo:

1 1 ITEM_ETC_GOLD_01 골드(소) xxx xxx xxx_TT_DESC 0 0 3 3 5 0 180000 3 0 1 0 0 255 1 1 0 0 0 0 0 0 0 0 0 0 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item\etc\drop_ch_money_small.bsr xxx xxx xxx 0 2 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1 표현할 골드의 양(param1이상) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 

1 4 ITEM_ETC_HP_POTION_01 HP 회복 약초 xxx SN_ITEM_ETC_HP_POTION_01 SN_ITEM_ETC_HP_POTION_01_TT_DESC 0 0 3 3 1 1 180000 3 0 1 1 1 255 3 1 0 0 1 0 60 0 0 0 1 21 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item\etc\drop_ch_bag.bsr item\etc\hp_potion_01.ddj xxx xxx 50 2 0 0 1 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 120 HP회복양 0 HP회복양(%) 0 MP회복양 0 MP회복양(%) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 

1 5 ITEM_ETC_HP_POTION_02 HP 회복약 (소) xxx SN_ITEM_ETC_HP_POTION_02 SN_ITEM_ETC_HP_POTION_02_TT_DESC 0 0 3 3 1 1 180000 3 0 1 1 1 255 3 1 0 0 1 0 110 0 0 0 2 39 -1 0 -1 0 -1 0 -1 0 -1 0 0 0 0 0 0 0 100 0 0 0 xxx item\etc\drop_ch_bag.bsr item\etc\hp_potion_02.ddj xxx xxx 50 2 0 0 2 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0 0 0 0 0 0 0 0 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 220 HP회복양 0 HP회복양(%) 0 MP회복양 0 MP회복양(%) -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx -1 xxx 0 0 

El texto entre el primer carácter (1) y el segundo carácter (1/4/5) no es un espacio en blanco, es una pestaña. No hay espacios en blanco en ese archivo de texto.

lo que quiero:

que desea obtener el segundo entero (En las tres líneas que he publicado anteriormente, el segundo enteros son 1,4 y 5) y la cadena en el centro de cada línea que indica el camino (Comienza con "item \" y termina con la extensión de archivo ".ddj").

Mi problema:

Cuando Google "El formato del texto de C#" - todo lo que consigo es cómo abrir un archivo de texto y cómo escribir un archivo de texto en C# .I no saben cómo buscar un texto dentro de un archivo de texto. Tampoco puedo buscar el primer entero, porque en caso de que sea un pequeño entero como en las tres líneas que publiqué arriba, no podré encontrar la ubicación corrent, porque podría existir "1" en una ubicación diferente.

Mi pregunta:

Sería la mejor Si escribo un programa que borrar nada, pero lo que necesito.

La otra manera en mi mente es buscar directamente dentro de ese archivo, pero como mencioné anteriormente, es posible que obtenga la ubicación incorrecta del segundo entero si es demasiado bajo.

Por favor sugiero algo, no puedo formatear todo esto a mano.

+7

"No hay espacios en blanco en ese archivo de texto" FYI: un carácter de tabulación es un espacio en blanco. Que quería decir "no hay espacios en ese archivo de texto" –

+0

Aquí está mi esfuerzo: [Analizar una línea y el establecimiento de coma entre hacer una cadena csv] [1] [1]: http : //stackoverflow.com/a/27244009/1147352 – DareDevil

Respuesta

48

OK, esto es lo que hacemos: abrir el archivo, leer línea por línea, y split por pestañas. Luego tomamos el segundo entero y recorremos el resto para encontrar el camino.

StreamReader reader = File.OpenText("filename.txt"); 
string line; 
while ((line = reader.ReadLine()) != null) { 
    string[] items = line.Split('\t'); 
    int myInteger = int.Parse(items[1]); // Here's your integer. 
    // Now let's find the path. 
    string path = null; 
    foreach (string item in items) { 
     if (item.StartsWith("item\\") && item.EndsWith(".ddj")) { 
      path = item; 
     } 
    } 

    // At this point, `myInteger` and `path` contain the values we want 
    // for the current line. We can then store those values or print them, 
    // or anything else we like. 
} 
+0

¡Gracias, lo probaré y daré su opinión! –

+0

Funciona genial, gracias! –

+1

Genial. No tengo un compilador de C# en esta máquina, así que tuve que aletear. Me alegra escuchar que funciona de la caja. –

5

Se podría hacer algo como:

using (TextReader rdr = OpenYourFile()) { 
    string line; 
    while ((line = rdr.ReadLine()) != null) { 
     string[] fields = line.Split('\t'); // THIS LINE DOES THE MAGIC 
     int theInt = Convert.ToInt32(fields[1]); 
    } 
} 

La razón por la que no encontró resultado relevante en la búsqueda de 'formato' es que la operación que está realizando se llama 'análisis'.

+1

Esto no obtiene "la cadena en el medio de cada línea que indica la ruta" (tomada directamente de la pregunta). –

+0

Muy bien, muy útil, pero ¿cómo puedo encontrar la cadena? –

+0

Es posible que necesite usar line.Split ("\ t" .ToCharArray()) según su versión (IIRC) Tenga cuidado, sin embargo. Si desea acceder al decimoquinto elemento de la línea, pero la línea en la que está trabajando solo contiene 12 elementos (por ejemplo), obtendrá una excepción. Protéjase contra este tipo de cosas tanto como sea posible. Además, una línea vacía te arrojará al desorden (sin juego de palabras) ya que el comando line.split ("\ t") devolverá una matriz con un solo elemento vacío. – ZombieSheep

0

Probar expresiones regulares. Puede encontrar un cierto patrón en su texto y reemplazarlo con algo que desee. No puedo darte el código exacto en este momento pero puedes probar tus expresiones usando esto.

http://www.radsoftware.com.au/regexdesigner/

0

Usted puede abrir el archivo y utilizar StreamReader.ReadLine para leer el archivo en línea por línea. Luego puede usar String.Split para dividir cada línea en pedazos (use un delimitador \ t) para extraer el segundo número.

Como la cantidad de elementos es diferente, deberá buscar en la cadena el patrón 'elemento \ *. Ddj'.

Para eliminar un elemento, podría (por ejemplo) mantener todos los contenidos del archivo en la memoria y escribir un nuevo archivo cuando el usuario haga clic en 'Guardar'.

32

Otra solución, esta vez haciendo uso de las expresiones regulares:

using System.Text.RegularExpressions; 

... 

Regex parts = new Regex(@"^\d+\t(\d+)\t.+?\t(item\\[^\t]+\.ddj)"); 

StreamReader reader = FileInfo.OpenText("filename.txt"); 
string line; 
while ((line = reader.ReadLine()) != null) { 
    Match match = parts.Match(line); 
    if (match.Success) { 
     int number = int.Parse(match.Group(1).Value); 
     string path = match.Group(2).Value; 

     // At this point, `number` and `path` contain the values we want 
     // for the current line. We can then store those values or print them, 
     // or anything else we like. 
    } 
} 

Esa expresión es un poco compleja, por lo que aquí se descompone:

^  Start of string 
\d+  "\d" means "digit" - 0-9. The "+" means "one or more." 
     So this means "one or more digits." 
\t  This matches a tab. 
(\d+) This also matches one or more digits. This time, though, we capture it 
     using brackets. This means we can access it using the Group method. 
\t  Another tab. 
.+?  "." means "anything." So "one or more of anything". In addition, it's lazy. 
     This is to stop it grabbing everything in sight - it'll only grab as much 
     as it needs to for the regex to work. 
\t  Another tab. 

(item\\[^\t]+\.ddj) 
    Here's the meat. This matches: "item\<one or more of anything but a tab>.ddj" 
+2

No sé cuáles de sus respuestas aceptar, ambas funcionan de maravilla. Me gusta esta más, porque me explicaste por qué y nunca antes había visto eso. –

+0

Si te gustan las expresiones regulares, te recomendaría usar algo como Perl la próxima vez que quieras procesar archivos como este. Está diseñado a su alrededor, y puede usarlo para formatear fácilmente su archivo de la manera que desee. –

+1

Samir Talwar: Creo que deberías convertirte en una maestra de expresiones regulares. La forma en que explicaste todo fue simplemente brillante.¡Nunca tuve un maestro tan detallado! +1 –

1

Como ya se ha mencionado, me altamente haría recomendamos usar expresiones regulares (en System.Text) para realizar este tipo de trabajo.

En combinación con una herramienta sólida como RegexBuddy, está considerando el manejo de situaciones complejas de análisis de registros de texto, además de obtener resultados rápidamente. La herramienta lo hace realmente fácil.

Espero que ayude.

0

Una forma que he encontrado realmente útil en situaciones como esta es ir a la vieja escuela y usar el proveedor Jet OLEDB, junto con un archivo schema.ini para leer archivos delimitados por tabuladores grandes usando ADO.Net. Obviamente, este método solo es útil si conoce el formato del archivo que se va a importar.

public void ImportCsvFile(string filename) 
{ 
    FileInfo file = new FileInfo(filename); 

    using (OleDbConnection con = 
      new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=\"" + 
      file.DirectoryName + "\"; 
      Extended Properties='text;HDR=Yes;FMT=TabDelimited';")) 
    { 
     using (OleDbCommand cmd = new OleDbCommand(string.Format 
            ("SELECT * FROM [{0}]", file.Name), con)) 
     { 
      con.Open(); 

      // Using a DataReader to process the data 
      using (OleDbDataReader reader = cmd.ExecuteReader()) 
      { 
       while (reader.Read()) 
       { 
        // Process the current reader entry... 
       } 
      } 

      // Using a DataTable to process the data 
      using (OleDbDataAdapter adp = new OleDbDataAdapter(cmd)) 
      { 
       DataTable tbl = new DataTable("MyTable"); 
       adp.Fill(tbl); 

       foreach (DataRow row in tbl.Rows) 
       { 
        // Process the current row... 
       } 
      } 
     } 
    } 
} 

Una vez que tenga los datos en un formato amigable como una tabla de datos, filtrando los datos que necesita se vuelve bastante trivial.

+1

Puede que necesite reemplazar JET con ACE y 4 con 12 en la cadena de conexión. Asegúrese de que esté compilado para 32 bits y no para 64 bits. – TamusJRoyce

Cuestiones relacionadas