如何在RichTextBox中反向查找文本?

4
我正在尝试编写一个搜索代码,允许您在两个方向(右和左)查找文本。我已经编写了一段可以搜索文本到右边的代码,但不能向左搜索。
以下是我要做的示例: example1 example2 example3 example4
比如说我找到了“example3”(向右走),现在我需要找到“example2”(向左走),该怎么编写代码呢?
问题:如何编写一个搜索文本向左(反向)的代码?
这是我为搜索文本向左尝试做的示例:
try
{
    richTextBox1.Focus();
    richTextBox1.Find(findwhat, findPos, RichTextBoxFinds.Reverse);
    richTextBox1.Select(findPos, findwhat.Length);
    findPos += findwhat.Length;
}
catch
{
    findPos = 0;
}

所以你想从文本末尾开始搜索?你能否详细解释一下你的意思?另外,你当前的代码有什么问题吗?它是否抛出异常? - Yacoub Massad
你可以先反转文本,然后再搜索它 ;-) - Markus Safar
假设我找到了“example3”,现在我需要找到“example2”,向左移动。我该如何编写代码?example1 example2 example3 example4 - David Fields
@JohnSmith 我知道你提出这个问题已经过去了好几年,但是请看我的回答来解决你的问题。 - VA systems engineer
4个回答

2

要向前搜索,请使用此代码:

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

要向后搜索,请使用以下代码:

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

1
我有同样的需求。这里是一个可工作的WinForms应用程序来演示。解决这个问题的灵感来自于CodeGuru上的"RichTextBox reverse find"线程。
在我的演示中,RTB预加载了文本并且是只读的,即,我没有尝试解决使用可编辑的RTB实现正向和反向查找所涉及的问题。

demo program screen shot

该表单具有以下控件:
  • 名为 objButtonFind 的 Forms.Button。文本 = "查找"
  • 名为 objTextBoxSearchWord 的 Forms.TextBox
  • 名为 objReverse 的 Forms.Checkbox。文本 = "反向"
  • 名为 objCheckBoxMatchCase 的 Forms.Checkbox。文本 = "匹配大小写"
  • 名为 objCheckBoxWholeWord 的 Forms.Checkbox。文本 = "全词匹配"
  • 名为 label1 的 Forms.Label。文本 = "RTB 起始位置"
  • 名为 objTextBoxStartPos 的 Forms.TextBox
  • 派生自 Forms.RichTextBox 的 Class ClsRichTextBox

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://dev59.com/MnI_5IYBdhLWcg3wDOhC
    /// </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; }
    }
}

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

就像Amritendu Mukhopadhyay所说,您需要使用此版本的“Find”。

Find(String, Int32, Int32, RichTextBoxFinds)
在RichTextBox控件中搜索文本,以查找控件内特定范围内的字符串,并应用于搜索的特定选项。

例如: richTextBoxTarget.Find(text, 0, findStart, RichTextBoxFinds.Reverse);


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接