65.9K
CodeProject 正在变化。 阅读更多。
Home

RegEx Tester - 正则表达式测试器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (60投票s)

2008 年 3 月 2 日

GPL3

6分钟阅读

viewsIcon

184520

downloadIcon

9250

它能帮助您开发并充分测试正则表达式在目标文本中的匹配情况。

RegEx Tester Screenshot

引言

使用 RegEx Tester,您可以充分开发和测试正则表达式在目标文本中的匹配情况。
它的用户界面旨在帮助您进行正则表达式开发;特别是那些庞大而复杂的正则表达式。
它使用并支持.NET RegEx 类中几乎所有可用的功能。
关于本文的撰写,我必须告诉您,英语不是我的母语,我在编辑、语法和拼写方面已尽力而为。您可能会发现写作错误,请告诉我,以便我进行更正。

功能列表

如果您有新的功能想法,可以将其编写出来,然后通过电子邮件发送给我,我将添加并注明您的贡献。如果您不知道如何正确实现这个想法,请在评论区发表,其他人(或我)可能会帮助您完成。让我们一起协作。

  • 异步执行,使用户能够中止执行。即使您创建了一个 灾难性回溯 的混乱。[作者:Pablo Oses]
  • 缩进输入模式,在执行前会去除 \r \n \t \v 和空格。这允许您以缩进和分格子的方式编写那些丑陋、冗长且晦涩的正则表达式。[作者:Pablo Oses]
  • 替换模式,启用 RegEx.Replace() 函数的使用。[作者:Pablo Oses]
  • Mono 兼容,使其能够在 Linux 上运行。[作者:Pablo Oses]
  • 测试文本高亮显示,基于结果选择。[作者:Davide Mauri]
  • F5 热键,无需改变光标位置或选择即可运行测试。摆脱鼠标![作者:Pablo Oses]
  • 匹配项列表,显示位置、长度以及匿名或命名捕获组。[作者:Davide Mauri 和 Pablo Oses]
  • 一个“复制到剪贴板”按钮,可选择“C# 代码片段”、“C# 转义 字符串”、“HTML 编码”或“纯文本”模式。[作者:Kurt Griffiths 和 Pablo Oses]
  • 调整窗口的三个部分(正则表达式、文本和结果)的大小。[作者:Pablo Oses]
  • 忽略大小写、多行、单行和区域设置不变选项。[作者:Davide Mauri 和 Pablo Oses]
  • 窗口大小调整和最大化功能。[作者:Kurt Griffiths 和 Pablo Oses]
  • 快速链接到正则表达式库和 ILoveJackDaniels 的备忘单。[作者:Pablo Oses]
  • 在测试文本中查找功能。[作者:Pablo Oses]
  • 执行时间测量。[作者:Pablo Oses]

这个程序有什么特别之处?

正如 balazs_hideghety 在他的评论中所说,市面上还有其他流行且出色的程序,如 RegEx buddy 或 Expresso,它们功能强大,似乎是正则表达式开发和测试的终极选择,但我仍然使用这个工具。为什么?我需要一个工具来帮助我设计 HTML 提取正则表达式。例如(截至 2009 年 5 月),如果您评估以下内容...

<td class="Frm_MsgSubject"><[^>]*?>(?<title>.*?)</a>.*?
	<td class="Frm_MsgAuthor"><[^>]*?>(?<author>.*?)</a>.*?
<td class="Frm_MsgDate"[^>]*?>(?<date>.*?)&.*?
	<td class="MsgBd BdSel ">.*?<td colspan="2">(?<body>[^<]*?)<"

...针对此页面的 HTML 源代码,您只需一次操作即可解析并提取页面中的所有评论及其相应的标题、正文、日期、用户等信息。当您从真实网站提取数据时,正则表达式非常强大。但问题是,所需的正则表达式非常长且极其晦涩难懂。您确实需要一些空格和缩进来使其清晰易懂,并且需要一个大窗口,提供足够的空间,以及一个能够处理大型原始 HTML 文档的测试文本框,这时这个工具就显得非常有用。

我在 RegExTester 中开发同样的正则表达式时,看起来是这样的。

<td\sclass="Frm_MsgSubject">    <[^>]*?    >    (?<title>.*?)    </a>
.*?
<td\sclass="Frm_MsgAuthor">        <[^>]*?    >    (?<author>.*?)    </a>
.*?
<td\sclass="Frm_MsgDate"    [^>]*?    >    (?<date>.*?)    &
.*?
<td\sclass="MsgBd\sBdSel\s">    .*?    <td\scolspan="2">    (?<body>[^<]*?)    <

正如您所见,我认为这种丑陋的正则表达式开发辅助工具是这个程序的核心功能。

程序的核心:AsyncTest()

这是该函数的一个简化版本,以便更容易阅读。

// Create the options object based on the UI checkboxes
RegexOptions regexOptions = new RegexOptions();
if (cbIgnoreCase.Checked) regexOptions |= RegexOptions.IgnoreCase;
if (cbCultureInvariant.Checked) regexOptions |= RegexOptions.CultureInvariant;
if (cbMultiLine.Checked) regexOptions |= RegexOptions.Multiline;
if (cbSingleLine.Checked) regexOptions |= RegexOptions.Singleline;
if (cbIndentedInput.Checked) regexOptions |= RegexOptions.IgnorePatternWhitespace;

// Creates the RegEx engine passing the RegEx string and the options object
Regex regex = new Regex(txtRegEx.Text, regexOptions);

// This executes the Regex and collects the results
// The execution isn't done until a member of the matchCollection is read.
// So I read the Count property for the regex to really execute from start to finish
MatchCollection matchCollection = regex.Matches(rtbText.Text);
int matchesFound = matchCollection.Count;

// Also do the RegEx replacement if the user asked for it
if (cbReplaceMode.Checked)
    rtbResults.Text = regex.Replace(rtbText.Text, txtRepEx.Text);

// Add the Capture Group columns to the Results ListView
int[] groupNumbers = regex.GetGroupNumbers();
string[] groupNames = regex.GetGroupNames();
string groupName = null;

foreach (int groupNumber in groupNumbers)
{
    if (groupNumber > 0)
    {
        groupName = "Group " + groupNumber;
        if (groupNames[groupNumber] != groupNumber.ToString()) 
            groupName += " (" + groupNames[groupNumber] + ")";
        lvResult.Columns.Add(groupName, 100, HorizontalAlignment.Left);
    }
}

// Process each of the Matches!
foreach (Match match in matchCollection)
{
    //Add it to the grid
    ListViewItem lvi = lvResult.Items.Add(match.ToString());
    lvi.SubItems.Add(match.Index.ToString());
    lvi.SubItems.Add(match.Length.ToString());
    for (int c = 1; c < match.Groups.Count; c++)
    {
        lvi.SubItems.Add(match.Groups[c].Value);
    }

    //Highlight the match in the RichTextBox
    rtbText.Select(match.Index, match.Length);
    rtbText.SelectionColor = Color.Red;
}

异步执行功能。有趣的开始!

我最初使用 BackgroundWorker 来编码,但不得不放弃它,因为它似乎只在你想要中止你代码中的一个长时间循环时有用……但当你调用一个需要很长时间才能完成的外部函数时,它就无能为力了。

所以,我从头开始用更底层的 Thread 管理重新编码了它,结果发现一旦完成,它比以前的技术更简单、更清晰。

private Thread worker; // The worker that really does the execution in a separate thread.

private void MainForm_Load(object sender, System.EventArgs e)
{
    // This is a critical line.
    // It allows the other thread to access the controls of this class/object.
    Control.CheckForIllegalCrossThreadCalls = false;
}

/// <summary>
/// Handle the multiple behaviors of the Test button based on its text
/// </summary>
private void btnTest_Click(object sender, System.EventArgs e)
{
    if (btnTest.Text == STOPPED_MODE_BUTTON_TEXT)
    {
        StartTest();
    }
    else if (btnTest.Text == RUNNING_MODE_BUTTON_TEXT)
    {
        AbortTest();
    }
}

/// <summary>
/// Prepare and launch the asynchronous execution using another thread
/// </summary>
private void StartTest()
{
    // Creates the separate Thread for executing the Test
    worker = new Thread(AsyncTest);

    // After this instruction if the worker hangs and this thread exits,
    // then nobody has to wait for the worker to finish. 
    // (e.g. The worker will be aborted if the user wants to close the app.)
    worker.IsBackground = true;

    // Start the Asynchronous Test function
    worker.Start();
}

/// <summary>
/// Instructs to abort the asynchronous execution of the Test.
/// </summary>
private void AbortTest()
{
    // This generates a ThreadAbortException at the worker function AsyncTest()
    if (worker.IsAlive) worker.Abort();
}

/// <summary>
/// This is the core of the app. The RegEx execution and processing function.
/// It's being run on a separated thread.
/// </summary>
private void AsyncTest()
{
    // Every line in this function is susceptible of a ThreadAbortException
    // which is how the user is able to stop it.
    try
    {
        sbpStatus.Text = "Test running...";
        // ***************************************
        // Here is the code that you already read 
        // in the previous section of this article
        // [The core of the program: AsyncTest()]
        // ***************************************
        sbpStatus.Text = "Test success.";
    }
    catch (ThreadAbortException)
    {
        sbpStatus.Text = "Test aborted by the user.";
    }
    catch (Exception e)
    {
        sbpStatus.Text = "Test aborted by an error.";
        // Any other Exception is shown to the user
        MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
    finally
    {
        // Restore the btnText functionality
        btnTest.Text = STOPPED_MODE_BUTTON_TEXT;
    }
}

程序历史

这个工具最初由 Davide Mauri(2003 年)编写。我在工作和个人项目中大量使用它。由于它是开源的,我开始添加我需要的新功能。有一天,程序已经大不相同,我想把所有这些改进都贡献给 Davide,所以我通过电子邮件联系了他,他允许我重新发布它,并给了我 Kurt Griffith 版本程序(2006 年)的链接。我将他的增强功能和我自己的功能进行了混合,并优化了用户界面。

推荐链接

其他链接

文章历史

  • 2011-05-21 - 文章已适配应用程序的新 3.2.0.0 版本
  • 2009-05-03 - 文章已适配应用程序的新 3.1.0.0 版本
  • 2008-03-08 - 将历史记录移到底部并更新了链接
  • 2008-03-05 - 文章已适配应用程序的新 3.0.0.0 版本,增加了异步执行功能
  • 2008-03-04 - 文章完全重写,以展示和注释项目中使用的代码片段
  • 2008-03-02 - 初始文章

程序历史

  • 2011-04-06 - 3.2.0.0 - 作者:Pablo Osés
    • 新功能
      • 检测捕获组内的多个捕获
    • 次要更改
      • 代码整理
      • 关于窗口中的贡献者更新
  • 2010-02-25 - 3.1.1.0 - 作者:Eric Lebetsamer
    • 新功能
      • 导出到 CSV
  • 2009-05-03 - 3.1.0.0 - 作者:Pablo Osés
    • 新功能
      • RegEx.Replace()
      • 上下文菜单图标
      • C# 代码片段复制
      • RichTextBox 的 WordWrap 功能
      • 执行时间
      • Mono 兼容
    • Bug 修复
      • 标签拼写错误
      • 新的 SuspendLayout 技术和大量代码重构
  • 2008-03-05 - 3.0.0.0 - 作者:Pablo Osés 
    • 新功能
      • 异步执行
      • 复制功能增强
      • 测试 Textbox 上下文菜单
      • 查找功能
  • 2008-03-03 - 2.0.1.0 - 作者:Pablo Osés
    • 新功能
      • 正则表达式备忘单 
    • Bug 修复
      • 多行行为
      • 性能问题 
      • 结果列表点击事件
  • 2008-03-02 - 2.0.0.0 - 作者:Pablo Osés
    • 新功能
      • 捕获组名称
      • 窗口最大化
      • 热键
      • 缩进输入
      • 区域设置不变
      • 可调整大小的面板
  • 2006-xx-xx - 1.0.0.3 - 作者:Kurt Griffiths 
    • 新功能
      • 复制和窗口大小调整
  • 2003-xx-xx - 1.0.0.3 - 作者:Davide Mauri
    • 原始版本
© . All rights reserved.