Text-Datei parsen

SirToby

Erfahrenes Mitglied
C# -- Text-Datei parsen (erweitert)

Hallo zusammen!

Ich stehe momentan vor einem Problem. Wie unschwer zu erkennen ist, parse ich Daten aus einer Datei und möchte sie auf bestimmte Faktoren untersuchen.

Das hier steht zB in der Datei:
Code:
EDDK  COLOGNE-BONN                              302 50.865917    7.142744      06_8067_50.860122_7.123781_064_--- 14L_12516_50.880470_7.129075_137_110.90 14R_6112_50.870845_7.120861_137_--- 24_8067_50.869670_7.155272_244_109.10 32L_6112_50.858506_7.138742_317_--- 32R_12516_50.855195_7.165692_317_109.70
EDDL  DUSSELDORF                                147 51.280925    6.757311      05L_8858_51.285314_6.752122_052_109.50 05R_9843_51.281236_6.755408_053_111.50 23L_9843_51.294286_6.782797_233_109.90 23R_8858_51.296736_6.776092_232_109.30
LIEO  COSTA_SMERALDA                             37 40.898611    9.517778      05_8022_40.893659_9.508070_054_109.90 23_8022_40.904147_9.528108_234_111.30


Nun habe ich mir folgendes Script dazu ausgedacht, die Einträge zu parsen:
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace ICAO
{
    class Program
    {
        static void Main(string[] args)
        {
            int rowCount = 1;
            bool gefunden = false;
            string userInput = string.Empty;
            const string FileName = @"D:\FSBuild\apts.txt";

            StreamReader FileStream = File.OpenText(FileName);

                Console.Write("ICAO-Code: ");
                userInput = Convert.ToString(Console.ReadLine());

                string searchString = userInput;
                string airportInfo = string.Empty;
                char[] filter = { ' ', '_' };


                while ((airportInfo = FileStream.ReadLine()) != null)
                {
                    if (airportInfo.Contains(searchString.ToUpper()))
                    {
                        string regReplace = Regex.Replace(airportInfo, @"\s+", " ");
                        string[] words = regReplace.Split(filter);
                        Console.WriteLine("{0} in Zeile {1} gefunden", searchString, rowCount);
                        Console.WriteLine("ICAO-Code: {0}\nAirport: {1}", words[0], words[1]);
                        for (int i = 0; i < words[1].Length + 10; i++)
                        {
                            Console.Write("-");
                        }
                        Console.WriteLine("");

                        for (int i = 5; i < words.Length - 1; i += 6)
                        {
                            Console.WriteLine("Runway: {0}", words[i]);
                            Console.WriteLine("Rwy-Length: {0}m", Math.Round(double.Parse(words[i + 1]) / 3.2808398950131233595800525));
                            //Console.WriteLine("Longitude: {0}", words[i + 2]);
                            //Console.WriteLine("Latitude: {0}", words[i + 3]);
                            Console.WriteLine("Rwy-Orientation: {0}°", words[i + 4]);
                            Console.WriteLine("ILS-Frequency: {0}MHz", words[i + 5]);
                            Console.WriteLine("-----");
                        }
                        gefunden = true;
                    }
                    rowCount++;
                }
                if (gefunden == false)
                {
                    Console.WriteLine("nicht gefunden");
                }
                FileStream.Close();
        }
    }
}

Das Problem ist, dass mein erdachtes System natürlich nur so lange funktioniert, als bis nicht ein bestimmter Airport auch noch '_' im Namen hat, wie im letzten Eintrag ersichtlich. Ich frage mich gerade, wie ich die Daten intelligenter aus der Datei parsen kann. Sinniger Weise liegen mir die Daten genau so wie oben dargestellt vor, also quasi mit Delimitern aus ' ' beliebiger Länge und '_'.

Vielen Dank schon mal für ein paar Lösungsansätze.

toby
 
Zuletzt bearbeitet:

ikosaeder

Teekannen-Agnostiker
Wie wäre es, wenn du das splitting in 2 Schritten machst. Zuerst splittest du den String anhand der Leerzeichen/tabs.
dann splittest du die Einträge für die Runways nochmal anhand der Unterstriche.
 

SirToby

Erfahrenes Mitglied
Habe mich nochmal hingesetzt, hin- und her analysiert und bin auf die Lösung gestoßen.

C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace ICAO
{
    class Program
    {
        static void Main(string[] args)
        {
            int rowCount = 1;
            bool gefunden = false;
            const double feetToMeter = 3.2808398950131233595800525;
            string userInput = string.Empty;
            const string FileName = @"D:\FSBuild\apts.txt";

            StreamReader FileStream = File.OpenText(FileName);

            Console.Write("ICAO-Code: ");
            userInput = Convert.ToString(Console.ReadLine());
            string searchString = userInput;
            string airportInfo = string.Empty;
            string airportname = string.Empty;
            string rwyInfoReplace = string.Empty;
            char[] filter = { ' ' };

            Console.WriteLine();

            while ((airportInfo = FileStream.ReadLine()) != null)
            {
                string[] icao = Regex.Split(airportInfo, "(?<icao>^[A-Z0-9]{4})");
                if (icao.Contains(searchString.ToUpper()))
                {
                    string regReplace = Regex.Replace(airportInfo, @"\s+", " ");
                    string[] words = regReplace.Split(filter);
                    airportname = words[1].Replace("_", " ");
                    for (int i = 5; i < words.Length - 1; i++)
                    {
                        rwyInfoReplace += Regex.Replace(words[i], @"_+", " ");
                        rwyInfoReplace += " ";
                    }
                    string rwyInfoTrim = rwyInfoReplace.Trim();
                    string[] rwyInfo = rwyInfoTrim.Split(filter);

                    Console.WriteLine("ICAO-Code: {0}\nAirport: {1}", words[0], airportname);
                    Console.WriteLine("AMSL: {0}m", Math.Round(double.Parse(words[2]) / feetToMeter));
                    Console.WriteLine("Latitude: {0}\nLongitude: {1}", words[3], words[4]);
                    for (int i = 0; i < words[1].Length + 10; i++)
                    {
                        Console.Write("-");
                    }

                    Console.WriteLine();
                    for (int i = 0; i < rwyInfo.Length - 1; i += 6)
                    {
                        Console.WriteLine("Runway: {0}", rwyInfo[i]);
                        Console.WriteLine("Rwy-Length: {0}m", Math.Round(double.Parse(rwyInfo[i + 1]) / feetToMeter));
                        Console.WriteLine("Latitude: {0}", rwyInfo[i + 2]);
                        Console.WriteLine("Longitude: {0}", rwyInfo[i + 3]);
                        Console.WriteLine("Rwy-Orientation: {0}°", rwyInfo[i + 4]);
                        Console.WriteLine("ILS-Frequency: {0}MHz", rwyInfo[i + 5]);
                        Console.WriteLine("-----");
                    }
                    gefunden = true;
                }
                rowCount++;
            }
            if (gefunden == false)
            {
                Console.WriteLine("nicht gefunden");
            }
            FileStream.Close();
        }
    }
}

Nun werden auch Such-Einträge korrekt gefiltert, zB 'EHAM', wo der String auch im eigentlichen Flughafennamen auftaucht.
Das mehrfache parsen ist zwar lästig, jedoch macht es das merkwürdige Datenformat notwendig.

Gibt es eventuell noch elegantere Methoden der Filterung?

vg,
toby
 
Zuletzt bearbeitet:

Neue Beiträge