问题
My program has to find specific words inside a RichTextBox and change their color (simple syntax highlighter). I am using Regex
to find the words.
I'm able to find them all but if my text contains 2 or more of the same word, I can only change the color of the first one, the other ones get untouched.
Dim words As String = "(in|handles|object|sub|private|dim|as|then|if|regex)"
Dim rex As New Regex(words)
Dim mc As MatchCollection = rex.Matches(RichTextBox1.Text.ToLower)
Dim lower_case_text As String = RichTextBox1.Text.ToLower
For Each m As Match In mc
For Each c As Capture In m.Captures
MsgBox(c.Value)
Dim index As Integer = lower_case_text.IndexOf(c.Value)
Dim lenght As Integer = c.Value.Length
RichTextBox1.Select(index, lenght)
RichTextBox1.SelectionColor = Color.Blue
Next
Next
My code needs to run from a button click. I think my problem is in the for each
loop, but I'm not sure.
I already have a few versions of it, but none working.
回答1:
This method can be simplified using some RegexOptions
RegexOptions.Compiled Or RegexOptions.IgnoreCase
RegexOptions.Compiled
:
Can be useful if the Text is long (faster execution at the expense of a slower startup).
RegexOptions.IgnoreCase
Performs a case-insensitive matching. You don't need to convert ToLower()
the Text.
RegexOptions.CultureInvariant
Could be added when necessary.
See the Regular Expression Options document for more informations.
Also, see the Regex.Escape() method, if parts of the pattern could contain some metacharacters.
Your code can be reduced to:
Dim pattern As String = "in|handles|object|sub|private|dim|as|then|if|regex"
Dim regx As New Regex(pattern, RegexOptions.Compiled Or RegexOptions.IgnoreCase)
Dim matches As MatchCollection = regx.Matches(RichTextBox1.Text)
For Each match As Match In matches
RichTextBox1.Select(match.Index, match.Length)
RichTextBox1.SelectionColor = Color.Blue
Next
回答2:
I think that's because lower_case_text.IndexOf(c.Value)
finds index only first match in string.
A quick hack would be to change lower_case_text
every for cycle.
Like: "dim something dim something"
After finding first dim, replace it with something same length like "000"
So your lower_case_text
will now be: "000 something dim something"
And then you will be able to get valid index of 2nd "dim"
It's not an elegant solution, but should work.
Hope it made seance.
回答3:
First, there's no need to use Captures
collection (and also parenthesis) because Capture
will hold same value as Match
. Second, you can use inline regex options (for instance (?i)
- set case-insensitive search) in the beginning of the regex pattern. The advantage of inline options is that you can set and cancel them in any part of your pattern (for instance (?-i)
- cancel case-insensitive search).
Dim input =
"If i = 10 Then
i = 0
Else
i = 5
End If"
Dim pattern = "(?i)in|handles|object|sub|private|dim|as|then|else|end|if|regex"
Dim mc = Regex.Matches(input, pattern)
For Each m As Match In mc
Dim index = m.Index
Dim length = m.Length
Next
来源:https://stackoverflow.com/questions/53680544/why-cant-i-change-the-color-of-repeated-words-in-a-richtextbox