Excel/CSV nach einem Wert durchsuchen und ausgeben - 2 Probleme

  • VB.NET

Es gibt 11 Antworten in diesem Thema. Der letzte Beitrag () ist von Dksksm.

    Excel/CSV nach einem Wert durchsuchen und ausgeben - 2 Probleme

    Hallo zusammen,

    ich hänge leider mal wieder an einem Problem fest.
    Ich habe eine sehr große Excel-Datei, welche ich als CSV umwandel, da auf dem System in welchem ich das Programm nutzen möchte kein Excel installiert ist. Um es aber zu erläutern, schreibe ich hier, wie die Exceldatei aufgebaut ist.
    In der Exceldatei sind Werte in sehr vielen Zellen Spalte A bis ca. AX und Zeilen bis ca. 900.

    Über mein Programm soll via TextBox ein Begriff gesucht werden, welcher aber nicht nur in Spalte A stehen kann, sondern auch in allen anderen Spalten.
    Wenn der gesuchte Begriff (Zahl oder Wort) gefunden wurde, dann soll aus dieser Zeile die Zellen aus Spalte A, B, D, AA und AB in Labels ausgegeben werden.

    Nun hänge ich jedoch bei 2 Proplemen fest :

    1. ich bekomme es nur hin, in Spalte A zu suchen. Wie kann ich in allen Spalten suchen?
    2. Wenn ich nach einer Zahl suche (zBsp. 1234) wird mir die Zeile angezeigt. Jedoch wird mir auch die selbe Zeile angezeigt, wenn ich nur nach zBsp. 12 suche. Die Zeile soll mir aber nur angegeben werden, wenn ich nach dem kompletten Wert suche (hier im Beispiel 1234). Wie kann ich das realisieren?

    Könnt ihr mir bitte den Code dafür zur Verfügung stellen?

    So sieht mein Code bisher aus und meine ExcelDatei.

    VB.NET-Quellcode

    1. Private Sub Suchen_Button_Click(sender As Object, e As EventArgs) Handles Suchen_Button.Click
    2. Try
    3. For Each row As String In File.ReadAllLines("Excel.csv")
    4. Dim Felder() As String = Split(row, ";")
    5. If Felder(0).Contains(TextBox_SuchEingabe.Text) Then
    6. Label_Feld_Spalte_A.Text = Felder(0)
    7. Label_Feld_Spalte_B.Text = Felder(1)
    8. Label_Feld_Spalte_D.Text = Felder(3)
    9. Label_Feld_Spalte_AA.Text = Felder(26)
    10. Label_Feld_Spalte_AB.Text = Felder(27)
    11. End If
    12. Next
    13. Catch ex As Exception
    14. MessageBox.Show("Fehlermeldung : " & ex.Message)
    15. End Try
    16. End Sub


    Du arbeitest rein string-basiert und Zeilenweise. Besser wäre natürlich hier mit einer typiserten Klasse von Daten oder mit einer entsprechenden Tabelle zu arbeiten.
    Das erst mal nur vorweg, ich verstehe schon, dass man sich da auch ein bischen "hocharbeiten" muss.

    Deine Vergleiche machst du mit Felder(0), also von vornherin nur mit dem ersten Feld und nicht mit row, ein String, der die Gesamt-Zeile enthält.
    Hier wäre ein Ansatz um auf "alles" zu prüfen.
    Dein Wunsch nach Werten zu suchen ist etwas schwieriger, weil du nicht typisiert und damit nur mit Strings suchst. Contains guckt halt nur ob eine Zeichenfolge "12" vorhanden ist. Du möchtest aber den Wert 12 suchen.
    Damit das untypisiert gelingen kann, müsstest du erst einmal ermitteln, ob du eine Zeichenkette oder einen Wert suchst; das könntest du auch vorgeben, zum Beispiel mit einer Checkbox, wo du mit angibst in row nach ";" & TextBox_SuchEingabe.Text & ";" zu suchen.
    Ich würde wirklich empfehlen typisiert zu arbeiten, dann aber wäre der Ansatz schon beim Auslesen der Excel-Tabelle zu verfolgen, wo du entweder mit Dataset > XML oder Klassendeklaration und Serialiserung verwenden solltest.
    Die Variante mit der Checkbox wäre natürlich möglich, jedoch will ich es dem Anwender so einfach wie möglich machen und ihn nicht noch überlegen lassen was er ankreuzen muss. Daher die Suche nach einem String.

    Mit

    Quellcode

    1. If Felder(0).Contains(TextBox_SuchEingabe.Text) Then
    wird "nur" in der ersten Spalte nach dem gesuchten Wort/Zahl gesucht. Deswegen habe ich auch schon es mit

    Quellcode

    1. If Felder(0 - 27).Contains(TextBox_SuchEingabe.Text) Then
    versucht, um Spalten A bis AB zu durchlaufen bei der Suche.
    Dann bekomme ich jedoch die Fehlermeldung "Der Index war außerhalb des Arraybereichs.".


    EDIT:

    habe es soeben hinbekommen.
    ich habe nach deinem Vorschlag einfach Felder in row geändert und somit funktioniert es.
    Somit ist die Erste Frage beantwortet.

    VB.NET-Quellcode

    1. If row.Contains(TextBox_SuchEingabe.Text) Then


    Nun wäre jedoch noch die 2 Frage das Problem :
    2. Wenn ich nach einer Zahl suche (zBsp. 1234) wird mir die Zeile angezeigt. Jedoch wird mir auch die selbe Zeile angezeigt, wenn ich nur nach zBsp. 12 suche. Die Zeile soll mir aber nur angegeben werden, wenn ich nach dem kompletten Wert suche (hier im Beispiel 1234). Wie kann ich das realisieren?

    Theoretisch müsste doch nur eine Abfrage gemacht werden : wenn die eingegeben/zu suchende Zeichenfolge gefunden wurde, dann prüfen ob die in diesem Feld (in der Excel/CSV) noch weitere Zeichen oder vor oder nach dem gesuchten steht, wenn ja weiter machen, wenn nicht stoppen.
    Die Frage ist nur, wie setzte ich diese Abfrage um?

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „zauber777“ ()

    ich hatte oben im ersten Post schon ein Bild eingefügt ganz unten hier noch einmal. einfach auf das symbol klicken. ich weiss leider nicht, wie ich hier direkt das bild anfüge
    Das Bild von der Excel und hier noch die CSV, mit welcher ich es aktuell teste.

    Quellcode

    1. Number;Text;Location;value 1;value 2;;;;;;;;;;;;;;;;;;;;;;Location3;value 3
    2. 1234;tex1;loc 1;1,2;5,1;;;;;;;;;;;;;;;;;;;;;;loc3 1;V3 1,2
    3. 567;tex2;loc 2;2,3;6,2;;;;;;;;;;;;;;;;;;;;;;loc3 2;V3 2,3
    4. 8910;tex3;loc 3;4;7;;;;;;;;;;;;;;;;;;;;;;loc3 3;V3 4



    Bilder
    • TestCSV.png

      4,58 kB, 429×137, 40 mal angesehen

    ErfinderDesRades schrieb:

    sowas kann man mit Regex basteln.

    Aber mal andere Frage: Wenn du nach 2 suchst, wird er in den Zeilen 1-3 Treffer finden.
    Welche der drei Zeilen soll nun in die Label kopiert werden?


    richtig, genau darin liegt das Problem, dass er die Zeile 1 dann ausgibt, weil "2" schon in der ersten Zeile gefunden wird.
    Eigentlich soll das Programm aber nur die Ausgabe in den Labels ausgeben, wenn der komplette Inhalt einer Zelle gesucht wird - in diesem Beispiel der CSV soll somit nur ein Ergebnis in die Labels kopiert werden, wenn nach "1234", "loc 1" oder "2,3"... gesucht wird, also der gesuchte Wert/Text auch wirklich komplett und nicht mehr oder weniger in einer Zelle vorkommt.
    Was aber bei dieser Situation?

    Quellcode

    1. Number;Text;Location;value 1;value 2;;;;;;;;;;;;;;;;;;;;;;Location3;value 3
    2. 1234;tex1;loc 1;1,2;2;;;;;;;;;;;;;;;;;;;;;;loc3 1;V3 1,2
    3. 567;tex2;loc 2;2;6,2;;;;;;;;;;;;;;;;;;;;;;loc3 2;V3 2,3
    4. 8910;tex3;loc 3;4;7;;;;;;;;;;;;;;;;;;;;;;loc3 3;V3 4
    Dann findet er die Zeilen #2 + #3, auch bei Anwendung von Regex.
    Aber in deine Labels kannst du nur eine der beiden Zeilen eintragen.
    @zauber777 Ich denke, Du musst erst in der Zeile nach dem exakten Treffer suchen und dann erste 'Split' für diese Zeile benutzen. So wie Es @Eierlein geschrieben hat.

    C# Console .net5

    C#-Quellcode

    1. using System;
    2. using System.IO;
    3. namespace DEIN_NAMESPACE_EDIT
    4. {
    5. class Program
    6. {
    7. static void Main(string[] args)
    8. {
    9. string TxbxSuchString = "567";
    10. var txt = File.ReadAllLines("csv.txt");
    11. foreach (var line in txt)
    12. {
    13. if (line.Contains(TxbxSuchString))
    14. {
    15. string[] cells = line.Split(";");
    16. Console.WriteLine($"Cell0:{cells[0]} - Cell1:{cells[1]} - ... ");
    17. }
    18. }
    19. }
    20. }
    21. }


    Autokonvertiert nach VB mit Telerik (ohne Gewähr):
    Spoiler anzeigen

    VB.NET-Quellcode

    1. Imports System
    2. Imports System.IO
    3. Namespace DeinNameSpace
    4. Class Program
    5. Private Shared Sub Main(ByVal args As String())
    6. Dim TxbxSuchString As String = "567"
    7. Dim txt = File.ReadAllLines("csv.txt")
    8. For Each line In txt
    9. If line.Contains(TxbxSuchString) Then
    10. Dim cells As String() = line.Split(";")
    11. Console.WriteLine($"Cell0:{cells(0)} - Cell1:{cells(1)} - ... ")
    12. End If
    13. Next
    14. End Sub
    15. End Class
    16. End Namespace​
    codewars.com Rank: 4 kyu
    Zum testen

    VB.NET-Quellcode

    1. Option Strict On
    2. Module Module1
    3. Sub Main()
    4. Dim arr(3) As String
    5. arr(0) = "Number;Text;Location;value 1;value 2;;;;;;;;;;;;;;;;;;"
    6. arr(1) = "1234;tex1;loc 1;1,2;5,1;;;;;;;;;;;;;;;;;;;;;;loc3 1;V3"
    7. arr(2) = "567;tex2;loc 2;2,3;6,2;;;;;;;;;;;;;;;;;;;;;;loc3 2;V3"
    8. arr(3) = "8910;tex3;loc 3;4;7;;;;;;;;;;;;;;;;;;;;;;loc3 3;V3 4"
    9. Dim suchtext As String
    10. ' suchtext = "1234"
    11. ' suchtext = "loc 3"
    12. suchtext = "V3"
    13. Dim Treffer As Boolean
    14. For i As Integer = 0 To 3
    15. Treffer = System.Text.RegularExpressions.Regex.IsMatch(arr(i), "(^|;)(" & suchtext & ")(;|$)")
    16. If Treffer Then Debug.Print(suchtext & " in Zeile " & i.ToString & " gefunden")
    17. Next
    18. End Sub
    19. End Module

    zauber777 schrieb:


    Deswegen habe ich auch schon es mit

    Quellcode

    1. If Felder(0 - 27).Contains(TextBox_SuchEingabe.Text) Then
    versucht, um Spalten A bis AB zu durchlaufen bei der Suche.
    Dann bekomme ich jedoch die Fehlermeldung "Der Index war außerhalb des Arraybereichs.".


    Der Code-Fetzen ist ja auch Bullshit, du müsstest in einer For-Schleife nach der Länge (Anzahl der Felder) jedes einzelene Feld prüfen.
    Aber die RegEx Ansätze die zwischenzeitlich hier aufgeschlagen sind gefallen mir persönlich eh besser.
    Ich hoffe du verstehst die Lösungsansätze und kannst dir später bei Erweiterungen selbst helfen.