Выделите список слов, используя регулярное выражение в c # - PullRequest
4 голосов
/ 17 марта 2009

У меня есть контент сайта, который содержит сокращения. У меня есть список признанных сокращений для сайта, вместе с их пояснениями. Я хочу создать регулярное выражение, которое позволит мне заменить все распознанные сокращения, содержащиеся в содержимом, на некоторую разметку.

Например:

содержание:

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.

(Это просто пример разметки для простоты).

Спасибо.

EDIT:

Ответ CraigD почти готов, но есть проблемы. Я только хочу соответствовать целым словам. Я также хочу сохранить правильную заглавную букву каждого слова, так что deb по-прежнему является deb, а Deb - по-прежнему Deb согласно исходному тексту. Например, этот вход:

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 ]

10 голосов
/ 17 марта 2009

Сначала вам нужно будет 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() - но я могу понять, почему регулярное выражение желательно: вы можете использовать его для принудительной замены «всего слова», только создав шаблон который использует якоря границы слова.

Вы можете пойти так далеко, чтобы построить единый шаблон из всех ваших экранированных входных строк, например:

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

и затем с помощью оценщика совпадений , чтобы найти правильную замену. Таким образом, вы можете избежать итерации входной строки более одного раза.

4 голосов
/ 17 марта 2009

Не уверен, насколько хорошо это масштабируется до большого списка слов, но я думаю, что он должен дать желаемый результат (хотя в вашем вопросе «результат» кажется идентичным «контенту»)?

В любом случае, дайте мне знать, если это то, что вы ищете

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();
        }
    }
}
1 голос
/ 17 марта 2009

Для тех, кто заинтересован, вот мое окончательное решение. Это для пользовательского контроля .NET. Он использует один шаблон с оценщиком совпадений, как предлагает Томалак, поэтому цикл 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>!
1 голос
/ 17 марта 2009

Я делаю в точности то, что вы ищете в моем приложении, и это работает для меня: параметр 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();
        }
1 голос
/ 17 марта 2009

Я сомневаюсь, что это будет работать лучше, чем обычное выполнение string.replace, поэтому, если производительность является критическим показателем (рефакторинг немного, чтобы использовать скомпилированное регулярное выражение). Вы можете сделать версию регулярного выражения как:

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

Вам необходимо реализовать GetReplaceForAbbr, который получает конкретный сопоставляемый abbr.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...