【问题标题】:Replace specific occurrence of text in a Regex Match替换正则表达式匹配中特定出现的文本
【发布时间】:2016-04-08 19:39:42
【问题描述】:

编辑: 此示例使用 html,但我需要这种类型的场景来处理其他类型的字符串。请将此视为正则表达式问题,而不是 html 问题。

假设我有一个这样的字符串:

<h1>Hello</h1><h2>World</h2><h3>!</h3>

我可能需要将文本替换为 any 其中一个标题标签,但让我们使用这个示例,我只想将 <h2> 修改为如下所示:

<h1>Hello</h1><div id="h2div"></div><h2>World</h2><h3>!</h3>

由于我可能需要替换任何标题,我只使用正则表达式搜索<h*。现在,我想让我的代码说“在你找到的所有<h* 标签中,只替换第二个”。

我以为我在这里找到了答案: How do I replace a specific occurrence of a string in a string?

不幸的是,结果不是我想要的。这是我的示例代码:

    private void button1_Click(object sender, EventArgs e)
    {
        //sample html file string:
        var htmlText = "<h1>Hello</h1><h2>World</h2><h3>!</h3>";

        //this text should replace <h2 with <div id="h2div"></div><h2"
        var replacementString = "<div id=\"" + "h2div" + "\"" + "</div>" + "<h2";
        int replacementIndex = 1; //only replace the second occurence found by regex.

        //find ALL occurrences of <h1 through <h6 in the file, but only replace <h2.
        htmlText = Regex.Replace(htmlText, "<h([1-6])", m => replacementString + replacementIndex++);

    }

我指定replacementIndex 还是replacementIndex++ 都没有关系,这是有道理的,但我只是想将代码与我找到的答案尽可能地匹配。

输出如下所示:

&lt;div id="h2div"&gt;&lt;/div&gt;&lt;h21&gt;Hello&lt;/h1&gt;&lt;div id="h2div"&gt;&lt;/div&gt;&lt;h22&gt;World&lt;/h2&gt;&lt;div id="h2div"&gt;&lt;/div&gt;&lt;h23&gt;!&lt;/h3&gt;

这里有很多不应该发生的事情。首先,应该只创建一个&lt;div&gt; 标签,而不是三个。其次,&lt;h 标签只被替换而不是&lt;h2,所以现在我们最终得到&lt;h21&lt;h22&lt;h23

从几个月前开始,我对正则表达式匹配的理解越来越好,但我对正则表达式匹配器和组真的不熟悉;我想这就是我在这里可能需要的。

您能否推荐我如何修复代码以便替换正则表达式匹配的特定索引?

【问题讨论】:

  • 我建议使用 HtmlAgilityPack 而不是 Regex 来处理 HTML。
  • 这只是一个例子。我有一些非 html 场景也需要这样做。

标签: c# regex


【解决方案1】:

抱歉不能用 C# 回答,但答案应该非常相似。对于您的特定情况,您的 JavaScript String.prototype.replace() 的正则表达式属性是 /(&lt;h1.+?\/h1&gt;)/,而替换属性是 "$1&lt;div id="h2div"&gt;" 所以;

var str = "<h1>Hello</h1><h2>World</h2><h3>!</h3>",
 repStr = str.replace(/(<h1.+?\/h1>)/,'$1<div id="h2div"></div>');

console.log(repStr) // "<h1>Hello</h1><div id="h2div"></div><h2>World</h2><h3>!</h3>"

或者,如果您不想使用捕获组,您仍然可以这样做

var repStr = str.replace(/<h1.+?\/h1>/,'$&<div id="h2div"></div>');

在这种特殊情况下基本上会给出相同的结果。

【讨论】:

  • 感谢您的回复。查看您的代码,我想您认为我只在寻找 h2,但我正在寻找正则表达式匹配中的第二次出现。在其他情况下,我可能正在寻找第三次出现。此外,字符串是一个示例,因此不能保证 h2 会立即出现在 h1 之后。
  • ... 我只想修改为如下所示:&lt;h1&gt;Hello&lt;/h1&gt;&lt;div id="h2div"&gt;&lt;/div&gt;&lt;h2&gt;World&lt;/h2&gt;&lt;h3&gt;!&lt;/h3&gt; 据我了解,您不想替换 h2 标签,但您插入的 div 的 id 为h2div 在 h1 和 h2 标签之间。所以这就是我所做的。对不起,如果我没有得到你想要的。
  • 你好。这样想.. 你可以找到任何类似&lt;hn 的标签,其中nn 是数字。对于这种特殊情况,我希望第二次出现正则表达式找到的任何内容。
【解决方案2】:

使用 MatchEvaluator?

private static int count = 0;
    static string CapText(Match m)
    {
        count++;

        if (count == 2)
        {
            return "<div id=\"h2div\"></div>" + m.Value;
        }

        return m.Value;
    }

private void button1_Click()
{
    var htmlText = "<h1>Hello</h1><h2>World</h2><h3>!</h3>";
    Regex rx = new Regex(@"<h([1-6])");
    var result = rx.Replace(htmlText, new MatchEvaluator(ClassOfThis.CapText));
}

【讨论】:

  • 我正在尝试对此进行测试,但不清楚您所说的 // do something here 是什么意思?
【解决方案3】:

我为此苦苦挣扎了一整天。自然地,提出问题有时会激发创造力,所以这就是我想出的解决方案。它使用 MatchCollection,然后使用字符串生成器插入字符串。字符串生成器可能对此有点矫枉过正,但它可以工作:-)

replacementIndex 定义要插入文本的匹配项。在我的例子中,正则表达式找到三个实例并修改找到的索引 1。从那里,我得到起始字符串索引并使用子字符串插入文本。这只是一个按钮的测试代码来证明功能。

    private void button1_Click(object sender, EventArgs e)
    {
        //sample text.
        var htmlText = "<h1>Hello</h1><h2>World</h2><h3>!</h3>";

        //the string builder will handle replacing the text.
        var stringBuilder = new StringBuilder(htmlText);

        //build the replacement text.
        var replacementString = "<div id=\"" + "h2div" + "\">" + "</div>";
        int replacementIndex = 1; //only replace the second occurence found by regex (zero-indexed).

        //find ALL occurrences of <h1 through <h6 in the file, but only replace <h2.
        var pattern = "<h([1-6])";
        MatchCollection matches = Regex.Matches(htmlText, pattern); //get all the matches.
        int startIndex = matches[replacementIndex].Index; //get the starting string index for the match.

        //insert the required text just before the found match.
        stringBuilder.Insert(startIndex, replacementString);

        //copy text to clipboard and display it on screen.
        htmlText = stringBuilder.ToString();
        System.Windows.Forms.Clipboard.SetText(htmlText);
        MessageBox.Show(htmlText);
    }

【讨论】:

    猜你喜欢
    • 2014-05-12
    • 2012-02-02
    • 2012-05-16
    • 1970-01-01
    • 2022-12-04
    • 1970-01-01
    • 2013-12-06
    • 2021-04-10
    • 1970-01-01
    相关资源
    最近更新 更多