Text durchsuchen und Ergebnis optisch hervorheben(RTB)

    • VB.NET
    • .NET (FX) 4.0

    Es gibt 5 Antworten in diesem Thema. Der letzte Beitrag () ist von razzzer530i.

      Text durchsuchen und Ergebnis optisch hervorheben(RTB)

      Moin Leute,

      ich habe jetzt öfter im Netz und auch hier mitbekommen, dass der Suche nach etwas sind, womit Sie bestimmte Zeichenfolgen wie 123 in 051234 finden und optisch hervorheben können.
      Jeder kennt die Suchoption in Outlook 2010+ wo der gefundene Text kursiv und gelb hinterlegt wird, sodass man direkt sieht, was gefunden wurde.
      Ich habe mich mal daran orientiert und eine Funktion geschrieben, mit der sich diese Suche auch in deinem Programm ganz leicht durchführen lässt.

      Aussehen wird das ganze dann später so:

      Das einzige was man dafür benötigt ist:

      -Eine WindosForm
      -Eine RichTextBox (RTB)
      -eine Textbox (TB)

      Fangen wir an:

      1. Wir definieren eine Funktion, die eine RTB und eine TB als Argument erwartet:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      2. End Function


      2. Wir erzeugen eine Variable, die uns später den gefundenen String zurückgibt:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      2. Dim strFoundText As String = ""
      3. return strFoundText
      4. End Function


      3. Sollte bereits ein Text markiert sein, dann löschen wir diese Markierung:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      2. Dim strFoundText As String = ""
      3. RTB.SelectionStart = 0
      4. RTB.SelectionLength = RTB.Text.Length
      5. RTB.SelectionBackColor = RTB.BackColor
      6. RTB.SelectionFont = RTB.Font
      7. Return strFoundText
      8. End Function


      4.Wir möchten ja nur Text markieren, wenn wir etwas zu suchen haben:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      2. Dim strFoundText As String = ""
      3. RTB.SelectionStart = 0
      4. RTB.SelectionLength = RTB.Text.Length
      5. RTB.SelectionBackColor = RTB.BackColor
      6. RTB.SelectionFont = RTB.Font
      7. If TB.Text IsNot "" Then
      8. End If
      9. Return strFoundText
      10. End Function


      5. Nehmen wir an, wir suchen das Wort "Test" und wissen nicht, ob es groß oder klein geschrieben ist aber geben in die Suche "test" ein, so finden wir natürlich keine Übereinstimmung im

      Text. Um das zu vermeiden, generieren wir 2 Variablen, die sowohl den Text der RTB als auch den Text der TB in Kleinbuchstaben umwandeln:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      2. Dim strFoundText As String = ""
      3. RTB.SelectionStart = 0
      4. RTB.SelectionLength = RTB.Text.Length
      5. RTB.SelectionBackColor = RTB.BackColor
      6. RTB.SelectionFont = RTB.Font
      7. If TB.Text IsNot "" Then
      8. Dim RTBTL As String = RTB.Text.ToLower
      9. Dim TBTL As String = TB.Text.ToLower
      10. End If
      11. Return strFoundText
      12. End Function


      6. Natürlich möchten wir, dass nur gesucht wird, wenn der Text unser gesuchtes Wort überhaupt findet:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      2. Dim strFoundText As String = ""
      3. RTB.SelectionStart = 0
      4. RTB.SelectionLength = RTB.Text.Length
      5. RTB.SelectionBackColor = RTB.BackColor
      6. RTB.SelectionFont = RTB.Font
      7. If TB.Text IsNot "" Then
      8. Dim RTBTL As String = RTB.Text.ToLower
      9. Dim TBTL As String = TB.Text.ToLower
      10. If RTBTL.Contains(TBTL) Then
      11. End If
      12. End If
      13. Return strFoundText
      14. End Function


      7. Mit der Funktion "String.IndexOf()" finden wir den 0-basierten Startindex unseres gesuchten Teilstrings. Die Funktion liefert uns allerdings nur den Index des ersten vorkommenden Treffers

      zurück. Wir benötigen also eine Schleife, in der wir das wiederholen, bis wir alle Vorkommen herausfinden können und eine Liste, in der wir die entsprechenden Indexe auflisten können.
      Um die Indexe auflisten zu können, benötigen wir 3 Variablen. Eine für die Länge des gesuchten Strings, eine zum hochzählen und eine die den Index zurückliefert:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Dim listindex As New List(Of Integer)
      2. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      3. Dim strFoundText As String = ""
      4. RTB.SelectionStart = 0
      5. RTB.SelectionLength = RTB.Text.Length
      6. RTB.SelectionBackColor = RTB.BackColor
      7. RTB.SelectionFont = RTB.Font
      8. If TB.Text IsNot "" Then
      9. Dim RTBTL As String = RTB.Text.ToLower
      10. Dim TBTL As String = TB.Text.ToLower
      11. If RTBTL.Contains(TBTL) Then
      12. Dim i1 As Integer = TBTL.Length
      13. Dim count As Integer = 0
      14. Dim index As Integer
      15. Do
      16. index = RTBTL.IndexOf(TBTL, index) + 1
      17. listindex.Add(index - 1)
      18. count += 1
      19. Loop While index > 0
      20. End If
      21. End If
      22. Return strFoundText
      23. End Function


      8. Jetzt haben wir eine Liste, in der Jeder Startindex des gesuchten Strings gelistet ist. Um jetzt jeden gefundenen String optisch zu selektieren, benötigen wir eine weitere Schleife.
      In diesem Fall ist das eine For Each Schleife, die jeden Index in unserer Liste abarbeitet und den entsprechenden Bereich markiert:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Dim listindex As New List(Of Integer)
      2. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      3. Dim strFoundText As String = ""
      4. RTB.SelectionStart = 0
      5. RTB.SelectionLength = RTB.Text.Length
      6. RTB.SelectionBackColor = RTB.BackColor
      7. RTB.SelectionFont = RTB.Font
      8. If TB.Text IsNot "" Then
      9. Dim RTBTL As String = RTB.Text.ToLower
      10. Dim TBTL As String = TB.Text.ToLower
      11. If RTBTL.Contains(TBTL) Then
      12. Dim i1 As Integer = TBTL.Length
      13. Dim count As Integer = 0
      14. Dim index As Integer
      15. Do
      16. index = RTBTL.IndexOf(TBTL, index) + 1
      17. listindex.Add(index - 1)
      18. count += 1
      19. Loop While index > 0
      20. For Each i In listindex
      21. Next
      22. End If
      23. End If
      24. Return strFoundText
      25. End Function


      9. In dieser Schleife setzen wir dann solange der index nicht -1 ist den Auswahlstart(SelectionStart) an die Position des aktuellen indexes und markieren die Länge, die wir Suchen.
      Wenn der markierte Text dem aus unserer Textbox entspricht, markieren wir diesen jetzt mit einer anderen Hintergrundfarbe und einer kursiven Schriftart. Beachtet werden muss dabei, dass
      das Suchen in den Variablen die aus Kleinbuchstaben bestehen stattfindet:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Dim listindex As New List(Of Integer)
      2. Public Function MarkText(ByVal RTB As RichTextBox, ByVal TB As TextBox)
      3. Dim strFoundText As String = ""
      4. RTB.SelectionStart = 0
      5. RTB.SelectionLength = RTB.Text.Length
      6. RTB.SelectionBackColor = RTB.BackColor
      7. RTB.SelectionFont = RTB.Font
      8. If TB.Text IsNot "" Then
      9. Dim RTBTL As String = RTB.Text.ToLower
      10. Dim TBTL As String = TB.Text.ToLower
      11. If RTBTL.Contains(TBTL) Then
      12. Dim i1 As Integer = TBTL.Length
      13. Dim count As Integer = 0
      14. Dim index As Integer
      15. Do
      16. index = RTBTL.IndexOf(TBTL, index) + 1
      17. listindex.Add(index - 1)
      18. count += 1
      19. Loop While index > 0
      20. For Each i In listindex
      21. If i <> -1 Then
      22. RTB.SelectionStart = i
      23. RTB.SelectionLength = i1
      24. If RTB.SelectedText.ToLower = TBTL Then
      25. strFoundText = RTB.SelectedText
      26. RTB.SelectionBackColor = Color.Yellow
      27. RTB.SelectionFont = New Font(RTB.Font, FontStyle.Italic)
      28. End If
      29. End If
      30. Next
      31. End If
      32. End If
      33. Return strFoundText
      34. End Function


      10. Aufgerufen wird die Funktion jetzt im TextChanged Ereignis der Textbox:
      Spoiler anzeigen

      VB.NET-Quellcode

      1. Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
      2. MarkText(RichTextBox1, TextBox1)
      3. End Sub




      Beispielprojekt:
      markstr.rar


      Für die die es interessiert oder die diesen Ansatz nutzen möchten, hier direkt die passende DLL dazu :)
      Steuerelement(DLL):
      SearchableRTB.rar
      ~Wir leben zwar alle unter dem gleichen Himmel, aber es haben nicht alle den gleichen Horizont~

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „razzzer530i“ ()

      Hmm - das klingt jetzt so, als sei razzers Ansatz nicht OOP.

      Wie dem auch sei - inne Programmiererei gibts das Prinzip "Composition over Inheritance", also wenn möglich solle man zusätzliche Features als zuschaltbare Komponenten umsetzen, und es eher vermeiden, neue, auf dieses Feature festgelegte Klassen zu erfinden.
      Weil es sind ja noch weitere ZusatzFeatures für Richtextbox denkbar, und wenn man da jedesmal eine neu Richtextbox für erfindet, dann hat man zum einen einen Haufen neuer Klassen, und zum anderen immer noch keine Richtextbox, die mehrere dieser Features unterstützt.

      Wohingegen wie gesagt bei "Composition over Inheritance" die Features nach Bedarf zuschaltbar wären.

      @razzer530i: Kannst du vlt. ein Testprojekt anhängen?
      @petaod wäre natürlich auch eine Möglichkeit. Habe diesen weg gewählt, weil ich oft gelesen habe, dass Leute danach gesucht haben wie man eben in einer RTB(X) Text sucht und markiert. So kann ich das besser veranschaulichen als direkt eine neue RTB mit Suchfunktion dahin zu schrieben Natürlich wäre das für die Endlösung auch klasse und ich denke, dass ich das auch Anhängen werde:) Als kleine Spielerei vlt.

      @ErfinderDesRades : Testprojekt ist angehangen und was die Vielzahl an möglichen RTBs angeht, stimme ich dir voll zu. Zwar praktisch für jeden Zweck die passende RTB zu haben aber eine RTB mit X Features finde ich sinnvoller.
      ~Wir leben zwar alle unter dem gleichen Himmel, aber es haben nicht alle den gleichen Horizont~

      ErfinderDesRades schrieb:

      als sei razzers Ansatz nicht OOP.
      So isses, denn in Snippet 1 wird eine RTB als Parameter übergeben.

      razzzer530i schrieb:

      Zwar praktisch für jeden Zweck die passende RTB zu haben
      ist echt suboptimal, Du verwendest auch keine Double-Variablen, die nur +-*/, nicht aber Sin(), Exp() usw.
      Oder Du hast eine Mathe-Matrizen-Bibliothek, die kann Inversion und Transponierung, nicht aber Matrizenmultiplikation
      usw.
      Du weißt, es ist "alles" drin in so einer Klasse / Bibliothek, auch wenn nicht immer alles genutzt wird. Wenn Du das programm dann erweiterst, ist die Funktionalitäz schon da. :thumbsup:
      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!