4

I'm trying to make a search code that allows you to find text in both directions (right and left). I've already made a code that searches text to the right but, not to the left.

Example of what I'm trying to do:

example1 example2 example3 example4

Lets say I found 'example3' (going to the right) and now I need to find example2 (going to the left) How will i make that code?

Question: How to make a code that searches text going to the left (reverse)?

Here is an example of what I've tried to do for searching text to the left:

try
{
    richTextBox1.Focus();
    richTextBox1.Find(findwhat, findPos, RichTextBoxFinds.Reverse);
    richTextBox1.Select(findPos, findwhat.Length);
    findPos += findwhat.Length;
}
catch
{
    findPos = 0;
}
Ghasem
  • 14,455
  • 21
  • 138
  • 171
David Fields
  • 157
  • 8
  • So you want to search from the end of the text? Can you please explain exactly what you mean? Also, what is the problem with your current code? Is it throwing an exception? – Yacoub Massad Jan 17 '16 at 21:02
  • You could reverse the text first and search for it afterwards ;-) – Markus Safar Jan 17 '16 at 21:03
  • Lets say I found 'example3', now I need to find example2. Going to the left. How will i make that code? example1 example2 example3 example4 – David Fields Jan 17 '16 at 21:19
  • @JohnSmith I acknowledge it's been years since you've asked the question, but see my answer for an answer to your question – VA systems engineer Apr 12 '19 at 12:28

4 Answers4

2

To search forward use this code:

int p;
p = RichTextBox1.Find(textToFind, RichTextBox1.SelectionStart + 1, RichTextBoxFinds.None);
if (p == -1)
    Interaction.MsgBox("Search text was not found.");

To search backward use this code:

int p;
p = RichTextBox1.Find(textToFind, 0, RichTextBox1.SelectionStart, RichTextBoxFinds.Reverse);
if (p == -1)
    Interaction.MsgBox("Search text was not found.");
and his dog
  • 149
  • 7
1

I had the same need. Here is a working WinForms app to demonstrate. Solving this was inspired by the thread "RichTextBox reverse find" on CodeGuru.

In my demo, the RTB is preloaded with text and is read-only, i.e., I didn't try to solve the issues associated with implementing find forward and reverse with an editable RTB.

demo program screen shot

The form has these controls:

  • Forms.Button named objButtonFind. Text = "Find"
  • Forms.TextBox named objTextBoxSearchWord
  • Forms.Checkbox named objReverse. Text = "Reverse"
  • Forms.Checkbox named objCheckBoxMatchCase. Text = "Match case"
  • Forms.Checkbox named objCheckBoxWholeWord. Text = "Whole word"
  • Forms.Lable named label1. Text = "RTB Start Pos"
  • Forms.TextBox named objTextBoxStartPos.
  • Class ClsRichTextBox derived from Forms.RichTextBox

ClsProgram.cs

using System;
using System.Windows.Forms;

namespace RichTextBoxFindWithReverse
{
    static class ClsProgram
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new ClsFormMain());
        }
    }

    /// <summary>
    /// https://stackoverflow.com/questions/1550293/stopping-textbox-flicker-during-update
    /// </summary>
    public static class ControlExtensions
    {
        [System.Runtime.InteropServices.DllImport("user32.dll")]
        public static extern bool LockWindowUpdate(IntPtr hWndLock);

        public static void Suspend(this Control control)
        {
            LockWindowUpdate(control.Handle);
        }

        public static void Resume(this Control control)
        {
            LockWindowUpdate(IntPtr.Zero);
        }
    }
}

ClsFormMain.cs

using System;
using System.Windows.Forms;

namespace RichTextBoxFindWithReverse
{
    public partial class ClsFormMain : Form
    {
        public ClsFormMain()
        {
            InitializeComponent();
            objRichTextBox.SelectionDataIsInteresting += ObjRichTextBox_SelectionDataIsInteresting;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            objRichTextBox.Text = "cat\ndog\nsnail\nOtter\ntigerelephant\ncatcatcat\ncatcatdog\ncatcatsnail\ncatcatOtter\ncatcattiger\ncatcatelephant\ncatdogcat\ncatdogdog\ncatdogsnail\ncatdogOtter\ncatdogtiger\ncatdogelephant\ncatsnailcat\ncatsnaildog\ncatsnailsnail\ncatsnailOtter\ncatsnailtiger\ncatsnailelephant\ncatOttercat\ncatOtterdog\ncatOttersnail\ncatOtterOtter\ncatOttertiger\ncatOtterelephant\ncattigercat\ncattigerdog\ncattigersnail";
            objButtonFind.Enabled = false;
            objReverse.Enabled = false;
            objCheckBoxMatchCase.Enabled = false;
            objCheckBoxWholeWord.Enabled = false;
        }

        private void ObjTextBoxSearchWord_TextChanged(object sender, EventArgs e)
        {

            if (objRichTextBox.Text.Length > 0 && objTextBoxSearchWord.Text.Length > 0)
            {
                objButtonFind.Enabled = true;
                objReverse.Enabled = true;
                objCheckBoxMatchCase.Enabled = true;
                objCheckBoxWholeWord.Enabled = true;
            }
            else
            {
                objButtonFind.Enabled = false;
                objReverse.Enabled = false;
                objCheckBoxMatchCase.Enabled = false;
                objCheckBoxWholeWord.Enabled = false;
            }
        }

        private void ObjButtonFind_Click(object sender, EventArgs e)
        {
            string options = "";

            if (!objCheckBoxMatchCase.Checked && !objCheckBoxWholeWord.Checked)
            {
                options = "Don't match case.\nMatch on partial word or whole word.";
            }
            else if (!objCheckBoxMatchCase.Checked && objCheckBoxWholeWord.Checked)
            {
                options = "Don't match case.\nMatch on whole word only.";
            }
            else if (objCheckBoxMatchCase.Checked && !objCheckBoxWholeWord.Checked)
            {
                options = "Match case.\nMatch on partial word or whole word.";
            }
            else //(objCheckBoxMatchCase.Checked && objCheckBoxWholeWord.Checked)
            {
                options = "Match case.\nMatch on whole word only.";
            }

            bool found = objRichTextBox.FindTextCustom(objTextBoxSearchWord.Text, objReverse.Checked, objCheckBoxMatchCase.Checked, objCheckBoxWholeWord.Checked);

            if (!found)
            {
                System.Windows.Forms.MessageBox.Show(string.Format("Can't find '{0}'.\n\nYour options:\n\n{1}", objTextBoxSearchWord.Text, options), "RichTextBox Find With Reverse", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        /// <summary>
        /// Display rich text box selection data
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ObjRichTextBox_SelectionDataIsInteresting(object sender, ClsRichTextBoxSelectionArgs e)
        {
            objTextBoxStartPos.Text = e.SelectionStart.ToString();
        }
    }
}

ClsRichTextBox.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace RichTextBoxFindWithReverse
{
    class ClsRichTextBox : RichTextBox
    {
        ClsFindMetadata objFindMetadata = null;
        ClsRichTextBoxSelectionArgs objRichTextBoxSelectionArgs = null;

        public ClsRichTextBox() : base()
        {
            SelectionChanged += ClsRichTextBox_SelectionChanged;
            objFindMetadata = new ClsFindMetadata();
            objRichTextBoxSelectionArgs = new ClsRichTextBoxSelectionArgs();
        }

        /// <summary>
        /// Clear the find data and highlighting (yellow background) if the user clicks on the text in the control
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ClsRichTextBox_SelectionChanged(object sender, EventArgs e)
        {
            ClearLastFind();

            objRichTextBoxSelectionArgs.Set(SelectionStart);
            OnSelectionDataIsInteresting(objRichTextBoxSelectionArgs);
        }

        /// <summary>
        /// If last find data is available (findIndex, findLength), clear the highlighting 
        /// </summary>
        public void ClearLastFind()
        {
            SelectionChanged -= ClsRichTextBox_SelectionChanged;
            ControlExtensions.Suspend(this);
            int saveSelectionStart = SelectionStart;

            if (objFindMetadata.findStart != -1)
            {
                objFindMetadata.ClearFind();
            }

            if (objFindMetadata.highLightStart != -1)
            {
                Select(objFindMetadata.highLightStart, objFindMetadata.highLightLength);
                objFindMetadata.ClearHighLight();
                SelectionBackColor = Color.White;
                SelectionLength = 0;
            }

            SelectionStart = saveSelectionStart;
            ControlExtensions.Resume(this);
            SelectionChanged += ClsRichTextBox_SelectionChanged;
        }

        // -----------------------------------------------------------------------
        // -----------------------------------------------------------------------
        // -----------------------------------------------------------------------

        /// <summary>
        /// If searchText is found, returns true. Otherwise, returns false
        /// </summary>
        /// <param name="searchText"></param>
        /// <param name="isReverse"></param>
        /// <param name="isMatchCase"></param>
        /// <param name="isWholeWord"></param>
        /// <returns></returns>
        public bool FindTextCustom(string searchText, bool isReverse, bool isMatchCase, bool isWholeWord)
        {
            int previousSaveFindIndex = objFindMetadata.findStart;
            int previousSaveFindLength = objFindMetadata.findLength;

            int localForwardOffset = 1;
            int saveSelectionStart = SelectionStart;
            int saveSelectionLength = SelectionLength;
            int indexToplineCharOne = GetCharIndexFromPosition(new Point(0, 0));
            bool found = false;

            SelectionChanged -= ClsRichTextBox_SelectionChanged;

            ControlExtensions.Suspend(this);

            SelectionStart = saveSelectionStart;

            if (saveSelectionStart == 0 && objFindMetadata.findStart == -1)
            {
                localForwardOffset = 0;
            }

            if (!isReverse && !isMatchCase && !isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, Math.Min(SelectionStart + localForwardOffset, TextLength), Text.Length, RichTextBoxFinds.None);
            }
            else if (!isReverse && !isMatchCase && isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, Math.Min(SelectionStart + localForwardOffset, TextLength), Text.Length, RichTextBoxFinds.WholeWord);
            }
            else if (!isReverse && isMatchCase && !isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, Math.Min(SelectionStart + localForwardOffset, TextLength), Text.Length, RichTextBoxFinds.MatchCase);
            }
            else if (!isReverse && isMatchCase && isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, Math.Min(SelectionStart + localForwardOffset, TextLength), Text.Length, RichTextBoxFinds.MatchCase | RichTextBoxFinds.WholeWord);
            }
            else if (isReverse && !isMatchCase && !isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, 0, SelectionStart, RichTextBoxFinds.Reverse);
            }
            else if (isReverse && !isMatchCase && isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, 0, SelectionStart, RichTextBoxFinds.WholeWord | RichTextBoxFinds.Reverse);
            }
            else if (isReverse && isMatchCase && !isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, 0, SelectionStart, RichTextBoxFinds.MatchCase | RichTextBoxFinds.Reverse);
            }
            else // (isReverse && isMatchCase && isWholeWord)
            {
                objFindMetadata.findStart = Find(searchText, 0, SelectionStart, RichTextBoxFinds.MatchCase | RichTextBoxFinds.WholeWord | RichTextBoxFinds.Reverse);
            }

            found = false;

            if (objFindMetadata.findStart >= 0)
            {
                if (!isReverse)
                {
                    if (saveSelectionStart <= objFindMetadata.findStart)
                    {
                        found = true;
                    }
                }
                else
                {
                    if (SelectionStart < saveSelectionStart)
                    {
                        found = true;
                    }
                }
            }

            if (found)
            {
                // ClearLastFind isn't applicable because it clears find metadata. Just clear the highlight
                if (previousSaveFindIndex != -1)
                {
                    Select(objFindMetadata.highLightStart, objFindMetadata.highLightLength);
                    objFindMetadata.ClearHighLight();
                    SelectionBackColor = Color.White;
                }

                objFindMetadata.highLightStart = objFindMetadata.findStart;
                objFindMetadata.highLightLength = objFindMetadata.findLength = searchText.Length;

                Select(objFindMetadata.findStart, objFindMetadata.findLength);
                SelectionBackColor = Color.Yellow;
                SelectionLength = 0;
            }
            else
            {
                objFindMetadata.ClearFind();
                SelectionLength = 0;
                SelectionStart = saveSelectionStart;
            }

            ControlExtensions.Resume(this);
            objRichTextBoxSelectionArgs.Set(SelectionStart);
            OnSelectionDataIsInteresting(objRichTextBoxSelectionArgs);
            SelectionChanged += ClsRichTextBox_SelectionChanged;
            Focus();
            return found;
        }

        /// <summary>
        /// Method used to invoke the event that is used to report RTB SelectionStart to interested parties
        /// https://learn.microsoft.com/en-us/dotnet/api/system.eventhandler-1?view=netframework-4.7.2
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSelectionDataIsInteresting(ClsRichTextBoxSelectionArgs e)
        {
            SelectionDataIsInteresting?.Invoke(this, e);
        }

        /// <summary>
        /// Event used to report RTB SelectionStart to interested parties
        /// </summary>
        public event EventHandler<ClsRichTextBoxSelectionArgs> SelectionDataIsInteresting;

        /// <summary>
        /// Class used to record state of find results and find highlighting
        /// </summary>
        private class ClsFindMetadata
        {
            internal int findStart = -1;
            internal int findLength = -1;

            internal int highLightStart = -1;
            internal int highLightLength = -1;

            internal void ClearFind()
            {
                findStart = -1;
                findLength = -1;
            }
            internal void ClearHighLight()
            {
                highLightStart = -1;
                highLightLength = -1;
            }
        }
    }

    /// <summary>
    /// Class used to report RTB SelectionStart to interested parties
    /// </summary>
    public class ClsRichTextBoxSelectionArgs : EventArgs
    {
        internal void Set(int selectionStart)
        {
            SelectionStart = selectionStart;
        }

        public int SelectionStart { get; set; }
    }
}
VA systems engineer
  • 2,856
  • 2
  • 14
  • 38
0
public string searchExpress = string.Empty;
public int findPos = 0;
private void reverseSearchButton_Click(object sender, EventArgs e)
    {
        // this is to check whether new search term is written in searchbox toolStripTextBox2

        string findterm = string.Empty;
        findterm = toolStripTextBox2.Text;

        if (findterm != searchExpress)
        {
            findPos = GetRichTextBox().TextLength;
            searchExpress = findterm;
        }



        if (toolStripTextBox2.Text.Length > 0)
        {
            try
            {



                findPos = GetRichTextBox().Find(findterm, 0, GetRichTextBox().SelectionStart , RichTextBoxFinds.Reverse);


                GetRichTextBox().Select(findPos, toolStripTextBox2.Text.Length);
                GetRichTextBox().ScrollToCaret();
                GetRichTextBox().Focus();
                findPos += toolStripTextBox2.Text.Length + 1;


            }
            catch
            {
                findPos = 0;
            }

        }
    }
0

Like Amritendu Mukhopadhyay say, You need use this version of "Find".

Find(String, Int32, Int32, RichTextBoxFinds)
Searches the text in a RichTextBox control for a string within a range of text within the control and with specific options applied to the search.

e.g. richTextBoxTarget.Find(text, 0, findStart, RichTextBoxFinds.Reverse);

pie
  • 169
  • 1
  • 8