Hallo,
habe eine Frage und bräuchte einen Tipp...
Ich habe eine *.csv Datei in der Verschiedene Einträge vorhanden sind. Aufbau sieht so aus:
Head1 Head2 Head 3
12345, 456, 1232,
...
.....
.......
Head5 Head6 Head7
8889, 8889, 56556,
...
.....
......
Ich möchte jetzt gerne nur die Zahlen vom "Head5" einlesen....
wie mach ich das am Besten?!
Ich lesen so lange mit dem StreamReader die Zeilen ein bis ich zum "Head5" komme und dann halt ab der nächsten Zeile bis zum Komma!? Oder liege ich falsch??
Hätte da jemand einen Schnipsel für mich!?
Grüße an Alle und Vielen Dank schon jetzt für Eure Mühe.....
Regex.
- performance is a feature -
Microsoft MVP - @Website - @AzureStuttgart - github.com/BenjaminAbt - Sustainable Code
Hallo zusammen,
zur Vollständigkeit [Artikel] Regex-Tutorial und https://regex101.com/
Gruss
Coffeebean
Microsoft MVP // Me // Blog // GitHub // @Egghead // All my talks // Speakerdeck
Zum Thema CSV und RegEx kann man sich folgenden Beitrag durchlesen
StackExchange/Software Engeniering: Can the csv format be defined by a regex?
Ein Beispiel für Regex.Split: https://www.dotnetperls.com/regex-split-numbers
Für den konkreten Fall dann "first match" oder "non-greedy" als Stichwort
Goalkicker.com // DNC Magazine for .NET Developers // .NET Blogs zum Folgen
Software is like cathedrals: first we build them, then we pray 😉
Okay, habe mir mal das regex angeschaut. So wie ich das sehe überprüfen ich damit nur, ob ich schon am Head5 angekommen bin und lese dann die Zahlen ein!?
Ist der Aufbau der "CSV"-Datei tatsächlich wie von dir geschildert? Falls ja, verwendest du einen eher merkwürdigen Aufbau. Reguläre stehen Überschriften / Bezeichner ja eher in der ersten Statts in der 15. Zeile.
Ansonsten: Du liest die Datei Zeilenweise ein und prüfst bei jeder Zeile ob du nun bei Head5 angekommen bist. Ist das der Fall, liest du ab der nächsten Zeile immer die Werte vor dem ersten Komma ein.
Oder habe ich etwas falsch verstanden?
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
ja, so solls sein und das scheinbar mit regex. Oder hast du einen anderen ansatz?
Hast Du eine Beispiel-Datei?
Ist denke ich besser, nur damit wir auch wirklich von dem gleichen Format ausgehen.
Wenn wenn es valides CSV ist, tuts auch eine Library wie der CsvHelper
Wenn Du mehrere Header-Zeilen auch zwischen den Daten hast, dann würde ich in folgenden Schritten vorgehen:
Jede Zeile nach Header-Zeilen prüfen. Ein Contains auf "Header5" könnte da schon reichen, wenn Du sicher sein kannst, dass das sonst nirgendwo steht.
Auf die gefundene Header-Zeile ein Split auf das Trennzeichen (Leerzeichen?) und anschließend heraus finden, an welcher Stelle im Array sich "Header5" befindet.
Ab dieser Zeile abwärz muss nun jede Zeile mit dem Trennzeichen (Komma?) gesplittet werden. In dem Array rufst Du nun den Wert ab, der den selben index wie der zuvor gesuchte Header hat.
Die Zeilen liest Du dann so lange, bis Du wieder eine Header-Zeile hast. Das erkennst Du z.B. daran, dass bei einem Split auf ein Komma nur ein Item raus kommt.
Ich hoffe, Du verstehst, wie ich das meine.
So kommst Du mMn. recht einfach ohne Regex aus und kannst ein Format wie das Folgende lesen.
Header1 Header2 Header3
1,2,3
1,2,3
Header4 Header5 Header6
1,2,3,4
1,2,3,4
Header7 Header8 Header9 Header10
1,2,3,4,5
1,2,3,4,5
NuGet Packages im Code auslesen
lock Alternative für async/await
Beim CleanCode zählen nicht die Regeln, sondern dass wir uns mit diesen Regeln befassen, selbst wenn wir sie nicht befolgen - hoffentlich nach reiflichen Überlegungen.
ja so hört sich das vernünftig an....jetzt noch eine Frage. Wenn ich mit StreamReader einlese, wie prüfe ich den darin dann die einzelnen wörter ab? Ich muss ja die Zeile einlesen und nach jedem Leerzeichen trennen, damit ich weiß das es sich um ein Wort handelt. Dann schreibe ich es in ein array und prüfe ob es das Wort Header5 ist....oder geht es eleganter?
Hallo,
ein Möglicher Ansatz wäre:
public class CSVReader
{
private List<string> rows = new List<string>();
public void Initialize(string csvPath)
{
// Prüfen ob Date existiert
if (File.Exists(csvPath))
{
using (FileStream stream = File.OpenRead(csvPath))
{
string currentLine = string.Empty;
// Datei Zeilenweise einlesen
using (TextReader reader = new StreamReader(stream))
{
while((currentLine = reader.ReadLine()) != null)
this.rows.Add(currentLine);
}
}
}
}
public IEnumerable<Int32> GetValues(string column)
{
int columnIndex = -1;
bool beginRead = false;
// Zeilen durchgehen und Werte suchen
foreach (string row in rows)
{
// Spalten splitten
string[] values = row.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// alle spalten durchgehen und prüfen ob der Wert dem Header entspricht
// wenn ja Spaltenindex nehmen und fortfahren
if (columnIndex < 0)
{
for (int i = 0; i < values.Length; i++)
{
if (values[i].Equals(column))
{
columnIndex = i;
break;
}
}
}
// wenn das lesen der Werte begonnen wurde (das heißt, ein gültiger Spaltenindex da ist) werden die Werte gelesen
if (columnIndex >= 0 && beginRead)
{
Int32 number = -1;
// versuchen den Wert in eine Zahl umzuwandeln, wenn es fehlschlägt abbruch
if (!Int32.TryParse(values[columnIndex], out number))
break;
// zahl zurück liefern
yield return number;
}
// lesen noch nicht begonnen und gültiger Spaltenindex
// dann lesen
else if (columnIndex >= 0)
beginRead = true;
}
}
}
Wissen ist nicht alles. Man muss es auch anwenden können.
PS Fritz!Box API - TR-064 Schnittstelle | PS EventLogManager |
Super....Danke hat alles funktioniert. Habe jetzt eine Kombi aus Regex und dem Schnipsel von inflames2k genommen....
Danke...