Grundlegende Gedanken beim Parsen von ASCI-Dateien

  • VB.NET

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Kasi.

    Grundlegende Gedanken beim Parsen von ASCI-Dateien

    Moin!

    ich muss immer mal wieder ASCII-Dateien wie folgende parsen um Werte zu finden.

    Quellcode

    1. H 0196 30.07.2001
    2. 0900 KMG Nord, Kisdorf, Modul cdiesia M„rz 96
    3. 0001 68745603.H35 23.09.1998 KMG Nord XXXXX
    4. 0100 Hansestadt-Lbeck Hansestadt-Lbeck Hansestadt Lbeck
    5. 1000 00142 Kleiner Bauhof
    6. 1001 0002 00142 Kleiner Bauhof
    7. 1002 0018 00014 Kleiner Bauhof
    8. 1003 KM 0.00 0000 0.00 0.00 0.000
    9. 1004 KM 0.00 0000 0.00 0.00 0.000
    10. 1005 1150 0 K
    11. 1006 I
    12. 1007 KM Stz 0.310 0.310 DN 0000
    13. 1010 45/98 15823 20813
    14. 1011 37.60 1
    15. 2000 0.00 HA 015823
    16. 2000 0.50 PA 015823
    17. 3000 3.60 15.60 LB U 015855 0.000 0.0000 0
    18. 3000 5.40 5.40 A- R 015912 0.000 0.0000 0
    19. 3000 10.60 10.60 AU-R 020017 0.000 0.0000 0


    oder

    Quellcode

    1. 0601 31.05.2012
    2. H
    3. HI 102.05.2012Lübeck XXXXX
    4. HI 2045180061 Grapengießerstr.
    5. HI 3045180061 045180061 045180062 0 300 STZ 0 O 57.30 032
    6. HI 4045180061 0.00 00000000 HA
    7. HI 4045180061 0.50 00000600 PA
    8. HI 4045180061 0.50 00003000 UAE-
    9. HI 4045180061 19.80 00025900 AUFO 1200
    10. HI 4045180061 36.70 00051500 RCF- 1.00 1.0
    11. HI 4045180061 39.80 00060600 RCFO 1.00 1.0 12
    12. HI 4045180061 40.10 00062000 AUFO 1200
    13. HI 4045180061 56.80 00081400 PE
    14. HI 4045180061 57.30 00083000 EH
    15. HI 4045180061 57.30 00083600 HL 57.30
    16. HI 2045180062 Grapengießerstr.
    17. HI 3045180062 045180062 045180063 0 300 STZ 0 O 53.90 032
    18. HI 4045180062 0.00 00084200 HA
    19. HI 4045180062 0.50 00085200 PA


    (mir ist leider unbekannt, wie ich Zitate lesbar formatiere wie bei ASCII-Dateien üblich)

    Ich lese oftmals die Zeilen ein, analyse einige und dann arbeite ich mit Flags die sich merken wo man gerade ist und machmal muss dann wieder eine Zeile vorher/später (oder mehr) einbeziehen um das Ergebnis zu finden.

    Das ist oftmals ein sehr aufwendiger und fehleranfälliger Process.

    Gibt es grundlegende Tipps, wie man das am besten umsetzen kann und sich das Leben nicht so schwer macht?

    Gruß Jan

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „jan99“ () aus folgendem Grund: Formatierung

    @jan99 Ist das CNC- oder CAD-Zeugs?
    Von wie vielen Zeilen reden wir?
    Wonach suchst Du?
    Was soll hinterher rauskommen?
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Die Daten sollten ja alle einem Schema folgen, weshalb ich daraus ein Datenmodell ableite und dann in dieses die Rohdaten einpasse: Datei Zeilenweise einlesen, durchlaufen, analysieren und verarbeiten.

    Beim Aufbau von solchen Daten evtl. verwendet Schemata:
    - Reihenfolge (z.B. Zeile X ist immer ABC)
    - Zeilenpräfix (z.B. Zeilen beginnend mit 011 = XYZ)
    - Trennzeichen (z.b. Semikolon)
    - Spaltenlängen, Zeichenzählen
    - ...
    "Gib einem Mann einen Fisch und du ernährst ihn für einen Tag. Lehre einen Mann zu fischen und du ernährst ihn für sein Leben."

    Wie debugge ich richtig? => Debuggen, Fehler finden und beseitigen
    Wie man VisualStudio nutzt? => VisualStudio richtig nutzen
    Lexer erstellen, der die Eingabe tokenisiert, wobei jeder Token sich durch das Charakteristikum auszeichnet (IstInteger, IstString, IstDouble, et cetera).
    Dann eine Grammatik formulieren, die diese "Sprache" (also die Charakteristika-Struktur) erzeugt, das heißt exemplarisch

    T -> Initialien, S
    T -> Integer, S

    S -> String, S
    S -> Zahl, S
    ... et cetera.

    Anhand dieser Regeln kannst du dann im Parser prüfen, ob die Eingabe der Grammatik genügt, oder nicht.
    Damit prüfst du aber im Grund erstmal nur die Korrektheit der Eingabe - ein Parser ist keine Suchmaschine, mit einem Parser kannst du halt eine Eingabe wie diese deine, prüfen, in eine weitaus lesbarere übertragen, oder andere/zusätzliche Strukturen beschreiben. Was genau versuchst du denn? Einen Wert zu finden, oder Werte zu extrahieren? Du könntest ein Baum erzeugen, wobei du halt Kriterien festlegen müsstest, wann ein Knoten ein "Elterknoten" und wann eines ein "Kindknoten" ist, den Baum entlang fahren, und alle diejenigen Kindknoten selektieren, die mit einem gewissen Elterknoten verbunden sind.
    Und Gott alleine weiß alles am allerbesten und besser.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „φConst“ ()

    Moin !

    erst einmal Danke für die Rückmeldungen.

    RodFromGermany schrieb:

    @jan99 Ist das CNC- oder CAD-Zeugs?
    Von wie vielen Zeilen reden wir?
    Wonach suchst Du?
    Was soll hinterher rauskommen?


    Es sind Daten aus Kanal-Inspektionen....

    Um es nochmal deutlich zu machen mir geht es darum, wie man so eine Sache grundsätzlich angeht. Die Aufgabe ist derzeit gelöst - aber ich möchte mir das Leben künftig einfacher machen.

    Hier einma die Anforderung an einem Beispiel - in einer Datei können mehrere Tage abgelegt sein.

    Hinweis: unter dem nachfolgenden Begriff Haltung wird die Verbindung zwischen zwei Kanalschächten verstanden


    • Zunächst ist der passende Tag zu finden (1) - HI 1[Datum]
    • Dann ist der Beginn der Haltung (045180061) zu finden (2)
    • Irgendwann wird eine Station (57.30) in der Haltung gesucht. (3)
    • wurde diese dann gefunden ist in der nachfolgenden Zeile zu prüfen, ob es an der Position (XYZ) einen bestimmten Wert (hier: HL an Nr.4) steht und dann wird (ermittelt)

    Anmerkung: hier dieses Beispiel genommen. Kann alles andere auch sein - nur der Aufbau ist gleich.

    Bisher bin ich durch den Code "gelaufen" und habe dann die einzelnen Zeilen geprüft. Dann habe ich mir Flags erstellt um zu dokumentieren wo ich gerade bin und wenn ich diese Ebene wieder verlassen habe. Aber ich irgendwie ist das sehr fehleranfällig ....

    Spoiler anzeigen

    VB.NET-Quellcode

    1. Dim Flag_Datum As Boolean = False
    2. For j As Integer = 0 To Zeilen.Count - 1
    3. Dim DataOfZeile As String = Zeilen(j) ' auslesen der Zeilen
    4. If DataOfZeile.Length >= 15 Then
    5. Dim Key_Datum As String = DataOfZeile.Substring(0, 14)
    6. Dim Flag_Station As Boolean = False
    7. If Key_Datum = "HI 1" & Datum Or Flag_Datum = True Then ' es ist der richtige Tag
    8. Flag_Datum = True
    9. ' Hier auf die Haltung prüfen
    10. If IsHaltung(DataOfZeile, HaltungNameTB2) = True Then
    11. Err_NoHltg = ""
    12. Flag_HaltungFound = True
    13. ' prüfen einer Zeile WV
    14. Dim Key_WV As String = DataOfZeile.Substring(0, 12)
    15. If ValiWVDataline(DataOfZeile, HaltungNameTB2, Stationierung, NodeKey.WV) = True Or Flag_Station = True Then ' es ist die richtige Station
    16. Err_NoWV = ""
    17. ' passend, dann nächste Zeile auslesen
    18. ' schreiben der CSV-DAtei
    19. Try
    20. DataOfZeile = Zeilen(j + 1)
    21. ' prüfen einer Zeile auf II
    22. If ValiWVDataline(DataOfZeile, HaltungNameTB2, Stationierung, NodeKey.II) = True Then
    23. If DataOfZeile.Length >= 57 Then
    24. Material = DataOfZeile.Substring(56).Trim
    25. 'Schreiben der CSV-Datei
    26. If ReportHasWrite = False Then WriteCSV(String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8}" & Environment.NewLine, Fid.ToString, Stationierung.ToString("0,00"), FileName, Datum, Material, Err_NoHltg, Err_NoWV, Err_NoMat, Err_Empty))
    27. ReportHasWrite = True
    28. Exit For
    29. Else
    30. If ReportHasWrite = False Then WriteCSV(String.Format("{0};{1};{2};{3};{4};{5};{6};{7};{8}" & Environment.NewLine, Fid.ToString, Stationierung.ToString("0,00").Replace(".", ","), FileName, Datum, Material, Err_NoHltg, Err_NoWV, "X", Err_Empty))
    31. ReportHasWrite = True
    32. Exit For
    33. End If
    34. End If
    35. Catch ' hier kommt der Fehler, wenn die Zeile nicht gefunden wurde
    36. Err_NoMat = "X"
    37. End Try
    38. Else
    39. Flag_Station = False
    40. End If
    41. Else ' Haltung nicht vorhanden
    42. 'wurde schon einmal gefunden und ist dann wieder verlassen worden, weil kein WV gefunden
    43. If Flag_HaltungFound = True Then Err_NoWV = "X"
    44. End If
    45. Else
    46. Flag_Datum = False
    47. Flag_Station = False
    48. End If
    49. Else
    50. ' Datenzeile vom Inhalt zu kurz
    51. End If
    52. Next



    Bin gespannt, ob und wie es einfacher geht - vom Konzept.

    Gruß Jan
    @jan99 Du hast die Frage
    Von wie vielen Zeilen reden wir?
    noch nicht beantwortet.
    Wenn Du die Datei zeilenweise in ein String-Array einliest, kannst Du mit dem Zeilenindex in dieser Datei navigieren.
    Wenn Du das Einlesen zeilenweise vornimmst (File.ReadLines()) und die Zugehörigkeit feststellst, kannst Du jeden Tag einzeln in ein Array einlesen und abarbeiten.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    prinzipiell braucht man zwei Dinge:
    1. Das Schema der Datei
      Man muss wissen, welcher Eintrag in welcher unter welchen Umständen Zeile was bedeutet.
      Sieht mir hier im Beispiel recht konfus aus, aber es geht ja ums Prinzip
      Möglich, dass man "im Code vor und zurück, und mit Flags dokumentieren" muss. Klingt erstmal, als ob es auch einfacher ginge, aber ohne zu wissen, welcher Eintrag in welcher Zeile unter welchen Umständen was bedeutet, kann man das nicht beurteilen
    2. Ein Datenmodell
      Die Dinge, die das Programm bearbeiten soll müssen in Code-Klassen nachgebildet sein - insbesondere auch in ihren relationalen Beziehungen untereinander.
    Jo, dann kann man die Datei ins Datenmodell einlesen.



    RodFromGermany schrieb:

    Von wie vielen Zeilen reden wir?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „ErfinderDesRades“ ()

    @jan99

    ich wundere mich immer wieder über solche Dateien, und würde auch gerne die Person
    fragen... wie bist du denn auf dieses tolle schema gekommen, war bestimmt schwer zu programmieren.... :cursing: 8|

    ich würde mal so anfangen, schau ob andere Dateien den Wert in der gleichen Cell haben

    VB.NET-Quellcode

    1. Public Class Form1
    2. Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    3. Dim filename = "E:\TestFolder\jan1.txt"
    4. Dim lines = (From line In IO.File.ReadAllLines(filename) _
    5. Select line.Split(New Char() {" "c, CChar(vbTab)}, StringSplitOptions.RemoveEmptyEntries)).ToArray
    6. With DataGridView1.Columns
    7. .Add(1, "Col1")
    8. .Add(2, "Col2")
    9. .Add(3, "Col3")
    10. .Add(4, "Col4")
    11. .Add(5, "Col5")
    12. .Add(6, "Col6")
    13. .Add(7, "Col7")
    14. .Add(8, "Col8")
    15. .Add(9, "Col9")
    16. .Add(10, "Col10")
    17. .Add(11, "Col11")
    18. .Add(12, "Col12")
    19. .Add(13, "Col13")
    20. .Add(14, "Col14")
    21. .Add(15, "Col15")
    22. End With
    23. For x As Integer = 0 To lines.Count - 1
    24. DataGridView1.Rows.Add(lines(x))
    25. Next
    26. DGVColumsAutoSize(DataGridView1, True)
    27. End Sub
    28. Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click
    29. Dim filename = "E:\TestFolder\jan2.txt"
    30. Dim lines = (From line In IO.File.ReadAllLines(filename) _
    31. Select line.Split(New Char() {" "c, CChar(vbTab)}, StringSplitOptions.RemoveEmptyEntries)).ToArray
    32. With DataGridView2.Columns
    33. .Add(1, "Col1")
    34. .Add(2, "Col2")
    35. .Add(3, "Col3")
    36. .Add(4, "Col4")
    37. .Add(5, "Col5")
    38. .Add(6, "Col6")
    39. .Add(7, "Col7")
    40. .Add(8, "Col8")
    41. .Add(9, "Col9")
    42. .Add(10, "Col10")
    43. .Add(11, "Col11")
    44. .Add(12, "Col12")
    45. .Add(13, "Col13")
    46. .Add(14, "Col14")
    47. .Add(15, "Col15")
    48. End With
    49. For x As Integer = 0 To lines.Count - 1
    50. DataGridView2.Rows.Add(lines(x))
    51. Next
    52. DGVColumsAutoSize(DataGridView2, True)
    53. End Sub
    54. Public Sub DGVColumsAutoSize(ByVal dgv As DataGridView, ByVal AutoSize As Boolean)
    55. If dgv Is Nothing Then
    56. Exit Sub
    57. End If
    58. Dim ColumnMode As DataGridViewAutoSizeColumnMode
    59. If AutoSize Then
    60. ColumnMode = DataGridViewAutoSizeColumnMode.AllCells
    61. Else
    62. ColumnMode = DataGridViewAutoSizeColumnMode.None
    63. End If
    64. With dgv
    65. For i As Integer = 0 To .Columns.Count - 1
    66. .Columns(i).AutoSizeMode = ColumnMode
    67. Next
    68. End With
    69. End Sub
    70. End Class



    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Kasi“ ()