RichTextBox editing

aeolian20

Member
Joined
Feb 13, 2010
Messages
12
Programming Experience
Beginner
I have hit a roadblock attempting to edit a RichTextBox and hoped someone had some insight.

This is the example text below:

a
b
hello
c
d
hello
e
f
hello
g

I would like to keep the 1st "hello". Then remove every other "hello" & the line above it. So it would read:

a
b
hello
c
e
g

I have managed to change the color of the 1st "hello" blue & every other one red w/ this code.

Dim findme As String = "hello"
Dim textend As Integer = RichTextBox1.TextLength
Dim index As Integer = 0
Dim lastindex As Integer = RichTextBox1.Text.LastIndexOf("hello")

While index < lastindex
RichTextBox1.Find(findme, index, textend, RichTextBoxFinds.None)

If index = 0 Then
Me.RichTextBox1.SelectionColor = Color.Blue
Else
Me.RichTextBox1.SelectionColor = Color.Red

End If
index = RichTextBox1.Text.IndexOf(findme, index) + 1

End While


Thanks for any insight.
 
I am starting to think I need to work backward and remove the last instance 1 at at time (& re dim the entire Richtextbox). This example will remove the last 2 instances but I do not know how many instances there will be in the real world so the true solution can not be hard coded this way:

VB.NET:
        Dim richtxt As String = RichTextBox1.Text
        Dim findme As String = "hello"
        Dim textend As Integer = RichTextBox1.TextLength
        Dim lastindex As Integer = RichTextBox1.Text.LastIndexOf("hello")

        RichTextBox1.Find(findme, lastindex, textend, RichTextBoxFinds.None)
        Me.RichTextBox1.SelectedText = ""

        Dim richtxt2 As String = RichTextBox1.Text
        Dim textend2 As Integer = RichTextBox1.TextLength
        Dim lastindex2 As Integer = RichTextBox1.Text.LastIndexOf("hello")

        RichTextBox1.Find(findme, lastindex2, textend2, RichTextBoxFinds.None)
        Me.RichTextBox1.SelectedText = ""
 
Finally worked out how to delete all but the 1st instance if anyone is interested:

(Still have not worked in deleting the line above it...guess that can wait until tomorrow)

VB.NET:
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        crop()
    End Sub

    Private Sub crop()
        Dim richtxt As String = RichTextBox1.Text
        Dim findme As String = "hello"
        Dim textend As Integer = RichTextBox1.TextLength
        Dim firstindex As Integer = RichTextBox1.Text.IndexOf("hello")
        Dim lastindex As Integer = RichTextBox1.Text.LastIndexOf("hello")

        If firstindex < lastindex Then
            textend = RichTextBox1.TextLength
            RichTextBox1.Find(findme, lastindex, textend, RichTextBoxFinds.None)
            Me.RichTextBox1.SelectedText = ""
            richtxt = RichTextBox1.Text
            textend = RichTextBox1.TextLength

            crop()

        End If
 
Here are two alternate solutions that may be applied, both give correct result for posted sample text.

This uses Regex:
VB.NET:
Dim matches As MatchCollection = Regex.Matches(Me.RichTextBox1.Text, "\n.+?\nhello")
For i As Integer = matches.Count - 1 To 1 Step -1
    Dim m As Match = matches(i)
    Me.RichTextBox1.Select(m.Index, m.Length)
    Me.RichTextBox1.SelectedText = String.Empty
Next
If you don't need to preserve formatting the lines can be processed off-control with this logic:
VB.NET:
Dim lines As New List(Of String)(Me.RichTextBox1.Lines)
Dim start As Integer = lines.IndexOf("hello") + 1
Dim delete As Boolean
For i As Integer = lines.Count - 1 To start Step -1
    If lines(i) = "hello" Then
        lines.RemoveAt(i)
        delete = True
    ElseIf delete Then
        lines.RemoveAt(i)
        delete = False
    End If
Next
Me.RichTextBox1.Lines = lines.ToArray
 
Thanks John, I think your second example may just do the job.

One more question though.

I actually need to delete 2 lines above (instead of one). I have tried to alter your code to do this but I think I am missing something in the logic.
 
This code deletes the line & 1 line above

VB.NET:
        For i As Integer = lines.Count - 1 To start Step -1

this code deletes the line & 2nd line above

VB.NET:
        For i As Integer = lines.Count - 2 To start Step -2]

Still trying to work out how to delete the line & both 1st and 2nd line above
 
VB.NET:
start = .... +2
VB.NET:
 ElseIf delete Then
        lines.RemoveAt(i)
        i -=1
        lines.RemoveAt(i)
Give those two adjustments some thought :eek: While it 'works' perfectly for sample data there is clearly a problem with this logic as the (i-1) will not honor the 'start' limit. This is something that can be fixed by checking the value.

A better approach that makes things easier is to simply expand the Boolean (two values possible) to a Integer (many values possible), like this:
VB.NET:
Dim deleteCount As Integer
For i As Integer = lines.Count - 1 To start Step -1
    If lines(i) = "hello" Then
        lines.RemoveAt(i)
        deleteCount = 2
    ElseIf deleteCount > 0 Then
        lines.RemoveAt(i)
        deleteCount -= 1
    End If
Next
The regex can also be expanded:
VB.NET:
((^|\n).+?){2}\nhello
 
Thanks a lot John. I have never used Regex before so took a while to find out I needed to set this up to use the statements:

VB.NET:
Imports System.Text.RegularExpressions

Regex seems to be getting the job done just fine. Thank you very very much.
:D
 
Thanks a lot John. I have never used Regex before so took a while to find out I needed to set this up to use the statements:

VB.NET:
Imports System.Text.RegularExpressions

Regex seems to be getting the job done just fine. Thank you very very much.
:D
I figured you'd get a squiggly line under first reference to MatchCollection and click the intellisense auto-fix option:
ErrorCorrectionOptions.png
 
Yes that is how i figured it out :D.

Now that I have plugged the code into a "real world" situation I had to change off Regex to make it work. No longer searching for "hello" but more like:

" N/*LOCN "

Some lines are just like that, others are like:

" N/*LCON xxxxxx"

What I am trying to figure out is how can I strip the last 6 characters off of EVERY line (I dont need that info and would rather it not show in the RTB at all).

Then I can run my code:

VB.NET:
        Dim lines As New List(Of String)(Me.RichTextBox1.Lines)
        Dim start As Integer = lines.IndexOf(" N/*LOCN          ") + 1
        Dim deleteCount As Integer
        For i As Integer = lines.Count - 1 To start Step -1
            If lines(i) = " N/*LOCN          " Then
                lines.RemoveAt(i)
                deleteCount = 3
            ElseIf deleteCount > 0 Then
                lines.RemoveAt(i)
                deleteCount -= 1
            End If
        Next
        Me.RichTextBox1.Lines = lines.ToArray
 
I have detected yet one more issue. Here is what I need:

1. Delete last 6 characters of every line
2. Find a line that "contains" N/*LOCN, delete it & the 2 lines above.

Upon further testing every line containing " N/*LOCN" is not the same some may be:

N/*LOCN xxxxxx
or
N/*LOCNyyyxxxxxx
 
I had to change off Regex to make it work
I recommend this place to learn regex: Regular-Expressions.info - Regex Tutorial, Examples and Reference - Regexp Patterns
1. Delete last 6 characters of every line
String.Remove Method (Int32) (System)
VB.NET:
s = s.Remove(s.Length - 6)
2. Find a line that "contains" N/*LOCN, delete it & the 2 lines above.
String.StartsWith Method (String) (System) would probably be a better choice than String.Contains method.
 
John, thanks a load for the intro to Regex. I read up on the link you posted & it enabled me to accomplish both of my tasks:

VB.NET:
        'Remove Last 6 of Each Line
        Dim last6 As MatchCollection = Regex.Matches(Me.RichTextBox1.Text, "(.){6}(?=\n)")
        For i As Integer = last6.Count - 1 To 0 Step -1
            Dim m As Match = last6(i)
            Me.RichTextBox1.Select(m.Index, m.Length)
            Me.RichTextBox1.SelectedText = String.Empty
        Next

        'Remove Redundant Lines
        Dim matches As MatchCollection = Regex.Matches(Me.RichTextBox1.Text, "((^|\n).+?){3}\n.+LOCN,EQPT AND FAC  FRAME ID   UNIT.*")
        For i As Integer = matches.Count - 1 To 1 Step -1
            Dim m As Match = matches(i)
            Me.RichTextBox1.Select(m.Index, m.Length)
            Me.RichTextBox1.SelectedText = String.Empty
        Next

:D
 
Back
Top