在不影响将来替换的情况下查找并替换几个单词

本文关键字:替换 单词 几个 查找 影响 将来 情况下 | 更新日期: 2023-09-27 17:59:49

我想做的是突出显示某种"禁止使用的单词"。

以下是我的值:

我有一个数组中的禁止字列表

{ "word1", "word2", "word3", "word4" }

我有一个代表评论的字符串

"i want to word1ban this word3 stupidword4 comment"

我想在html粗体标记(<b> </b>)中突出显示这些内容。例如,这个注释字符串将变成:

"i want to <b>word1</b>ban this <b>word3</b> stupid<b>word4</b> comment"

实际上,我做这件事的方式是使用正则表达式替换,它运行得很好,除了一件事让我很讨厌

foreach (var word in words)
{
    value = Regex.Replace(value, string.Format(@"{0}", Regex.Escape(HttpUtility.HtmlEncode(word))), "<b>" + word + "</b>", RegexOptions.IgnoreCase);
}

这个问题也取决于数组中单词的顺序,是其中一个被禁止的单词是否会影响您的替换(<b></b>

例如,如果您将其添加到禁止的单词中:<b

根据代码,第一次迭代结果将是:

"i want to <b>word1</b>ban this <b>word3</b> stupid<b>word4</b> comment"

然后替换为<b之后它将是:

"i want to <b><b</b>>word1</b>ban this <b><b</b>>word3</b> stupid<b><b</b>>word4</b> comment"

我不想影响我的替代者。我想知道我们该怎么做。我尝试在regex中添加异常以排除替换中的<b></b>,但没有成功。

在不影响将来替换的情况下查找并替换几个单词

忽略问题的整个"HTML"方面,只是从的角度来解决它

我想找到并替换几个单词,但我不希望我所做的替换影响未来的替换

你可以做一件事:一次做所有的替换!

var pattern = "(" + String.Join("|", words.Select(w => Regex.Escape(w))) + ")";
// e.g. (word1|word2|word3|word4)
value = Regex.Replace(
    value,
    pattern,
    "<b>$1</b>",
    RegexOptions.IgnoreCase);

在一般情况下,这里需要的是替换输入中的一些术语,而不是迄今为止生成的输出中的一些。这并不难手动完成,但首先你必须确定哪个术语优先被替换。

假设你有一本术语和替换词的词典,选择替换哪个术语的策略是"替换最接近输入开头的术语;如果多个术语出现在同一位置,则替换最长的术语"。这里有一种方法:

string ReplaceWithoutOverlap(string input, IDictionary<string, string> replacements)
{
    var processedCharCount = 0;
    var sb = new StringBuilder();
    while (processedCharCount < input.Length) {
        var replacement = replacements
                .Select(r => Tuple.Create(r.Key, input.IndexOf(r.Key, processedCharCount)))
                .Where(t => t.Item2 != -1)
                .OrderBy(t => t.Item2)
                .ThenByDescending(t => t.Item1.Length)
                .FirstOrDefault();
        if (replacement == null)
        {
            break;
        }
        sb.Append(input, processedCharCount, replacement.Item2 - processedCharCount);
        sb.Append(replacements[replacement.Item1]);
        processedCharCount = replacement.Item2 + replacement.Item1.Length;
    }
    sb.Append(input.Substring(processedCharCount));
    return sb.ToString();
}

在实际操作中查看

当然,这并不是你想要在这里做的(事实上,用一个正则表达式同时替换所有内容可能是最方便的),但你可以看到它是如何工作的。