代码之家  ›  专栏  ›  技术社区  ›  David Conlisk

使用C中的正则表达式突出显示单词列表#

  •  4
  • David Conlisk  · 技术社区  · 17 年前

    我有一些包含缩写的网站内容。我有一个网站的公认缩写列表,以及他们的解释。我想创建一个正则表达式,它允许我用一些标记替换内容中所有已识别的缩写。

    例如:

    内容:

    This is just a little test of the memb to see if it gets picked up. 
    Deb of course should also be caught here.

    缩写:

    memb = Member; deb = Debut; 

    结果:

    This is just a little test of the [a title="Member"]memb[/a] to see if it gets picked up. 
    [a title="Debut"]Deb[/a] of course should also be caught here.

    (这只是简单的标记示例)。

    谢谢。

    编辑:

    克雷格的答案就在眼前,但也有一些问题。我只想把整句话拼起来。我还想保持每一个词的正确大写替换,使代布仍然是代布,代布仍然是代布根据原文。例如,此输入:

    This is just a little test of the memb. 
    And another memb, but not amemba. 
    Deb of course should also be caught here.deb!
    
    5 回复  |  直到 17 年前
        1
  •  10
  •   Tomalak    17 年前

    首先你需要 Regex.Escape() 所有输入字符串。

    然后,您可以在字符串中查找它们,并通过记住的标记迭代替换它们:

    string abbr      = "memb";
    string word      = "Member";
    string pattern   = String.Format("\b{0}\b", Regex.Escape(abbr));
    string substitue = String.Format("[a title=\"{0}\"]{1}[/a]", word, abbr);
    string output    = Regex.Replace(input, pattern, substitue);
    

    编辑:我问是否简单 String.Replace() 这还不够——但我明白了为什么需要regex:您可以使用它来强制“全字”替换,只需生成一个使用单词边界锚定的模式。

    您可以从所有转义的输入字符串构建单个模式,如下所示:

    \b(?:{abbr_1}|{abbr_2}|{abbr_3}|{abbr_n})\b
    

    然后使用 match evaluator 找到合适的替代品。这样可以避免多次迭代输入字符串。

        2
  •  4
  •   Conceptdev    17 年前

    不确定这将在多大程度上扩展到一个单词列表,但我认为它应该给出您想要的输出(尽管在您的问题中,“结果”似乎与“内容”相同)?

    不管怎样,如果这是你想要的,请告诉我。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text.RegularExpressions;
    
    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
                var input = @"This is just a little test of the memb to see if it gets picked up. 
    Deb of course should also be caught here.";
                var dictionary = new Dictionary<string,string>
                {
                    {"memb", "Member"}
                    ,{"deb","Debut"}
                };
                var regex = "(" + String.Join(")|(", dictionary.Keys.ToArray()) + ")";
                foreach (Match metamatch in Regex.Matches(input
                   , regex  /*@"(memb)|(deb)"*/
                   , RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
                { 
                    input = input.Replace(metamatch.Value, dictionary[metamatch.Value.ToLower()]);
                }
                Console.Write (input);
                Console.ReadLine();
            }
        }
    }
    
        3
  •  1
  •   eglasius    17 年前

    我怀疑它的性能会比普通的string.replace好,所以如果性能是关键的度量(重构一点以使用编译后的regex)。您可以按如下方式执行regex版本:

    var abbrsWithPipes = "(abbr1|abbr2)";
    var regex = new Regex(abbrsWithPipes);
    return regex.Replace(html, m => GetReplaceForAbbr(m.Value));
    

    您需要实现getreplaceforabbr,它接收要匹配的特定abbr。

        4
  •  1
  •   Stefan    17 年前

    我做的正是你在我的应用程序中寻找的,这对我很有用: str参数是您的内容:

    public static string GetGlossaryString(string str)
            {
                List<string> glossaryWords = GetGlossaryItems();//this collection would contain your abbreviations; you could just make it a Dictionary so you can have the abbreviation-full term pairs and use them in the loop below 
    
                str = string.Format(" {0} ", str);//quick and dirty way to also search the first and last word in the content.
    
                foreach (string word in glossaryWords)
                    str = Regex.Replace(str, "([\\W])(" + word + ")([\\W])", "$1<span class='glossaryItem'>$2</span>$3", RegexOptions.IgnoreCase);
    
                return str.Trim();
            }
    
        5
  •  1
  •   David Conlisk    17 年前

    对于任何感兴趣的人,这是我的最终解决方案。它用于.NET用户控件。它使用一个带有匹配评估器的单一模式,如tomalak所建议的,因此没有foreach循环。这是一个很好的解决方案,它为示例输入提供了正确的输出,同时为匹配的字符串保留了正确的大小写。

    public partial class Abbreviations : System.Web.UI.UserControl
    {
        private Dictionary<String, String> dictionary = DataHelper.GetAbbreviations();
    
        protected void Page_Load(object sender, EventArgs e)
        {
            string input = "This is just a little test of the memb. And another memb, but not amemba to see if it gets picked up. Deb of course should also be caught here.deb!";
    
            var regex = "\\b(?:" + String.Join("|", dictionary.Keys.ToArray()) + ")\\b";
    
            MatchEvaluator myEvaluator = new MatchEvaluator(GetExplanationMarkup);
    
            input = Regex.Replace(input, regex, myEvaluator, RegexOptions.IgnoreCase);
    
            litContent.Text = input;
        }
    
        private string GetExplanationMarkup(Match m)
        {
            return string.Format("<b title='{0}'>{1}</b>", dictionary[m.Value.ToLower()], m.Value);
        }
    }
    

    输出如下所示。注意,它只匹配完整的单词,并且套管保留在原始字符串中:

    This is just a little test of the <b title='Member'>memb</b>. And another <b title='Member'>memb</b>, but not amemba to see if it gets picked up. <b title='Debut'>Deb</b> of course should also be caught here.<b title='Debut'>deb</b>!