如何在不同情况下使用Regex.Replace

时间:2019-11-27 10:30:59

标签: c# regex

我之前也有类似的问题,但最终却无法真正获得正确的答案。

我有一个函数,可以将我在输入字段中写的内容与从数据库中获取的内容进行匹配。它还带有一个始终为“ em”的参数。

函数如下:

public static string Hightlight(this string input, string phrase, string tag)
    {
        foreach (var item in phrase.Split(' '))
        {
            if (string.IsNullOrWhiteSpace(item))
                continue;

            input = Regex.Replace(input,
                string.Format("(?<phrase>{0})", HttpUtility.HtmlEncode(item)),
                string.Format("<{0}>${{phrase}}</{0}>", tag), RegexOptions.IgnoreCase);
        }

return input
}

这一直有效,直到人们尝试编写Martina E。 然后,正则表达式会尝试使用<em>标签将我正在构建的输入中的E与所有e相匹配。

有更好的方法吗? 我希望输入的最终结果是这样的:<em>Martina</em><em>E</em>

1 个答案:

答案 0 :(得分:1)

我建议为正则表达式替换创建一个正则表达式,该正则表达式将与标签之外的整个单词匹配名称:

return Regex.Replace(
            input, 
            string.Format(@"(<{0}>.*?</{0}>)|(?<!\w)(?:{1})(?!\w)", tag,
                string.Join("|", 
                    phrase.Trim().Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries)
                        .Select(x => Regex.Escape(HttpUtility.HtmlEncode(x)))
                )
            ), 
            m => m.Groups[1].Success ? m.Groups[1].Value : string.Format("<{0}>{1}</{0}>", tag, m.Value), 
            RegexOptions.IgnoreCase
        );

请参见C# demo

简而言之:

  • (<{0}>.*?</{0}>)|(?<!\w)(?:{1})(?!\w)将产生与(<em>.*?</em>)|(?<!\w)(?:Emma|E)(?!\w)Emma匹配的正则表达式,如E,该正则表达式不包含单词字符或<em>与之间的子字符串</em>在组1中捕获后者
  • phrase.Trim().Split(new[] {" "}, StringSplitOptions.RemoveEmptyEntries).Select(x => Regex.Escape(HttpUtility.HtmlEncode(x))))用空格分隔phrase,以删除空白项目,在对HTML进行编码后,使用Regex.Escape将每个项目转义以用于正则表达式模式,然后
  • string.Join("|", ...)将项目与管道字符连接起来。
  • 如果组1匹配,
  • m => m.Groups[1].Success ? m.Groups[1].Value : string.Format("<{0}>{1}</{0}>", tag, m.Value)用组1内容(现有的标记文本)替换,否则,添加标记的匹配。