2009-05-13 9 views
22

Per formattazione del testo intendevo qualcosa di più complicato.Come analizzare un file di testo con C#

Inizialmente ho iniziato ad aggiungere manualmente le 5000 linee del file di testo per il quale sto facendo questa domanda, nel mio progetto.

Il file di testo, dispone di 5000 linee con differenti esempio length.For:

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 

Il testo tra il primo carattere (1) ed il secondo carattere (1/4/5) non è uno spazio bianco, è una scheda. Non ci sono spazi bianchi in quel file di testo.

quello che voglio:

voglio ottenere il secondo numero intero (Nei tre linee che ho postato sopra, la seconda interi sono 1,4 e 5) e la stringa al centro di ogni riga che indica il percorso (Inizia con "item \" e termina con l'estensione del file ".ddj").

Il mio problema:

Quando Google "La formattazione del testo C#" - tutto quello che ottiene è come aprire un file di testo e come scrivere un file di testo in C# .i non sanno come cercare il testo all'interno di un file di testo.Inoltre non riesco a cercare il primo numero intero, perché nel caso sia un numero intero piccolo come nelle tre righe che ho postato sopra, non sarò in grado di trovare la posizione corretta, perché potrebbe esistere "1" in una posizione diversa.

La mia domanda:

sarebbe la migliore Se scrivo un programma che elimina qualsiasi cosa, ma quello che mi serve.

L'altro modo nella mia mente è cercare direttamente all'interno di quel file, ma come ho detto sopra, potrei ottenere la posizione sbagliata del secondo intero se è troppo bassa.

Si prega di suggerire qualcosa, non posso formattare tutto questo a mano.

+7

"Non ci sono spazi bianchi in quel file di testo" FYI: un carattere di tabulazione è uno spazio bianco. Volevi dire "non ci sono spazi in cui file di testo" –

+0

Ecco il mio sforzo: [Analisi di una linea e l'impostazione virgola tra fare una stringa csv] [1] [1]: http : //stackoverflow.com/a/27244009/1147352 – DareDevil

risposta

48

OK, ecco quello che facciamo: aprire il file, leggere riga per riga, e dividemmo da tabulazioni. Quindi prendiamo il secondo intero e passiamo attraverso il resto per trovare il percorso.

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

Grazie, lo proverò e quindi darò un feedback! –

+0

Funziona alla grande, grazie! –

+1

Grande. Non ho un compilatore C# su questa macchina, quindi ho dovuto armarlo. Felice di sentirlo funzionare fuori dalla scatola. –

5

Si potrebbe fare qualcosa di simile:

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]); 
    } 
} 

Il motivo non avete trovato risultato rilevante per la ricerca di 'formattazione' è che l'operazione che si sta eseguendo si chiama 'parsing'.

+1

Questo non ottiene "la stringa nel mezzo di ogni riga che indica il percorso" (presa direttamente dalla domanda). –

+0

OK, molto utile, ma come trovo la stringa? –

+0

Potrebbe essere necessario utilizzare line.Split ("\ t" .ToCharArray()) a seconda della versione (IIRC) Fare attenzione, tuttavia. Se si desidera accedere al 15 ° elemento sulla linea, ma la linea su cui si sta lavorando contiene solo 12 elementi (ad esempio) si otterrà un'eccezione. Proteggi il più possibile questo tipo di cose. Inoltre, una linea vuota ti farà cadere in disordine (nessun gioco di parole) dato che il comando line.split ("\ t") restituirà un array con un solo elemento vuoto. – ZombieSheep

0

Prova espressioni regolari. Puoi trovare un determinato pattern nel tuo testo e sostituirlo con qualcosa che desideri. Non posso darti il ​​codice esatto adesso ma puoi testare le tue espressioni usando questo.

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

0

È possibile aprire il file e utilizzare StreamReader.ReadLine per leggere il file riga per riga. Quindi puoi usare String.Split per spezzare ogni linea in pezzi (usa un delimitatore \ t) per estrarre il secondo numero.

Poiché il numero di elementi è diverso, è necessario cercare nella stringa il motivo "elemento \ *. Ddj".

Per eliminare un elemento è possibile (ad esempio) mantenere tutti i contenuti del file in memoria e scrivere un nuovo file quando l'utente fa clic su "Salva".

32

Un'altra soluzione, questa volta facendo uso di espressioni regolari:

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. 
    } 
} 

Quell'espressione un po 'complesso, ecco perché è infranto:

^  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

Non so quale delle tue risposte accettare, entrambe funzionano alla grande. Questo mi piace di più, perché hai spiegato perché e non l'avevo mai visto prima! –

+0

Se ti piacciono le espressioni regolari, ti consiglio di utilizzare qualcosa come Perl la prossima volta che desideri elaborare file come questo. È progettato intorno a loro e puoi usarlo per formattare facilmente i tuoi file nel modo che preferisci. –

+1

Samir Talwar: Penso che dovresti diventare un insegnante di espressioni regolari. Il modo in cui hai spiegato tutto era semplicemente geniale.Non ho mai avuto un insegnante così dettagliato! +1 –

1

Come è già accennato, altamente consiglia di utilizzare l'espressione regolare (in System.Text) per ottenere questo tipo di lavoro.

In combinazione con uno strumento solido come RegexBuddy, si sta cercando di gestire qualsiasi situazione di analisi di record di testo complesso, oltre a ottenere risultati rapidamente. Lo strumento lo rende davvero facile.

Spero che questo aiuti.

0

Un modo che ho trovato davvero utile in situazioni come questa è quello di andare a scuola vecchia e utilizzare il provider OLEDB Jet, insieme a un file schema.ini per leggere file di grandi dimensioni delimitati da tabulazioni nell'utilizzo di ADO.Net. Ovviamente, questo metodo è davvero utile solo se si conosce il formato del file da importare.

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 volta che hai i dati in un bel formato come un DataTable, filtrando i dati necessari diventa abbastanza banale.

+1

Potrebbe essere necessario sostituire JET con ACE e 4 con 12 nella stringa di connessione. Assicurati che sia compilato per 32-bit e non 64-bit. – TamusJRoyce

Problemi correlati