0

I'm trying to find a way to get the index of every specified word in a string:

Input:
String representing the word to look for

Desired behaviour:
Run a method and give it the index (Something like a foreach)

I need it to find the word so that I can color the specifed word throughout.

Like this (im using bolding here but imagine it is color)

Input :

string text = "I want to throw my pc off the window. I want to go party" 

string word = "want"

markup(text, word , richtextbox) 

Output:

I want to throw my pc off the window. I want to go party


Google didn't give any helpfull results.

Rufus L
  • 36,127
  • 5
  • 30
  • 43
Luke
  • 31
  • 5
  • Language is C# → Right, you have a C# tag and don't need to put it as heading. – Reza Aghaei Feb 07 '20 at 19:01
  • You mean google didn't mention the `IndexOf` method at all? – Rufus L Feb 07 '20 at 19:02
  • Are looking for `String.Replace`? – Reza Aghaei Feb 07 '20 at 19:02
  • `IndexOf` only returns the first instance of the substring. He should use `Regex.Matches` instead. – TheBatman Feb 07 '20 at 19:03
  • [How to highlight wrapped text in a control](https://stackoverflow.com/a/48257170/7444103). See the notes and check the warning in one of the test methods. – Jimi Feb 07 '20 at 19:05
  • Example: [Syntax Highlighting in Rich TextBox Control - Part 1](https://www.c-sharpcorner.com/article/syntax-highlighting-in-rich-textbox-control-part-1/) – Reza Aghaei Feb 07 '20 at 19:05
  • you can create a function which will run in loop if `IndexOf` function founds an occurance, after you find the first occurance just pass on the index value to second search and thus your loop will check the entire string for same keyword. – Vicky Salunkhe Feb 07 '20 at 19:14

3 Answers3

1

You can use the IndexOf method to get the index of one string within another. It takes an argument that specifies where to start looking, so you can continually call it in a loop and just increment the starting index on each iteration. If it returns -1, it means the string was not found, so we can use that as a condition for the loop.

For example, this method takes in a RichTextBox control and a string to search for, and it will highlight all instances of the search text within the RTB text:

private static void HighlightText(RichTextBox rtb, string text, Color? highlight = null)
{
    if (rtb == null || rtb.TextLength == 0 || text == null || text.Length == 0) return;

    // Find the first index of the text
    var index = rtb.Text.IndexOf(text);
    var length = text.Length;
    var color = highlight ?? Color.Red;  // Use Red if no color was specified

    // While we found a match
    while (index > -1)
    {
        // Highlight it
        rtb.SelectionStart = index;
        rtb.SelectionLength = length;
        rtb.SelectionColor = color;

        // Then try to find the next index of the text (starting after the previous one)
        index = rtb.Text.IndexOf(text, index + length);
    }
}

For sample usage, drop a RichTextBox, a TextBox, and a Button control on the form, and add this code to the Button.Click event:

private void button1_Click(object sender, EventArgs e)
{
    HighlightText(richTextBox1, textBox1.Text);
}

Output

enter image description here


Update

If you want to highlight multiple items at once, you could create an overload of the method that takes in an array of strings and then calls the method above for each item in the array:

private static void HighlightItems(RichTextBox rtb, string[] items, Color? highlight = null)
{
    if (items == null || items.Length == 0) return;

    foreach (var item in items)
    {
        HighlightText(rtb, item, highlight);
    }
}

A sample way to call this would be to take the text in textbox1 and split it on the semi-colon character. Then we can pass the resulting array to our overload method above:

private void button1_Click(object sender, EventArgs e)
{
    // Un-highlight the text first
    richTextBox1.SelectAll();
    richTextBox1.SelectionColor = Color.Black;

    // Call highlight with an array of strings created by 
    // splitting textbox1.Text on the ';' character
    var multipleItems = textBox1.Text.Split(';');
    HighlightItems(richTextBox1, multipleItems);
}

Output

enter image description here

Rufus L
  • 36,127
  • 5
  • 30
  • 43
  • Is there a way to modify the code snippet to accept multiple tags or i should just call it a bunch of times? (Sorry if its a dumb question im a bit new to UI) – Luke Feb 07 '20 at 21:39
  • Sure, you could write another method with a similar signature that takes in an array of strings and then inside that method call the other one for each item in the array. I've posted a sample. – Rufus L Feb 07 '20 at 22:06
0

Regexes are your friend. IndexOf only gets the first instance of the substring, but we want all of them.

        string text = "I want to throw my pc off the window. I want to go to a party.";

        string word = "want";

        string pattern = $@"({word})";

        MatchCollection matches = Regex.Matches(text, pattern);

        foreach(Match match in matches)
        {
            Console.WriteLine(match.Index); // print indexes
        }

Instead of printing the indexes as in this example, you can use the indexes to highlight the text.

TheBatman
  • 770
  • 4
  • 10
0

it should work if you want to find word indexes to operate some change to your richtextbox :

void Main()
{
   string text = "I want to throw my pc off the window. I want to go party";
   string word = "want";

    var indexes = GetWordIndexes(text,word)
    foreach (var inx in indexes)
    {
        markup(text, inx, richtextbox)
    }
}

public IEnumerable<int> GetWordIndexes(string text, string word)
{
    int wordLength = word.Length;
    for (int i = 0; i < text.Length; i++)
    {
        if (!(text.Length - wordLength < i) && text.Substring(i,wordLength) == word) 
            yield return i;
    }
}

AliReza Sabouri
  • 4,355
  • 2
  • 25
  • 37