This article has been localized into Russian by the community.
Поиск/Замена с классом Regex
Мы уже обсуждали класс Regex и как его использовать, когда мы хотим выполнить поиск по строке в предыдущей статье. Регулярные выражения отлично подходят для этого, но другой вариант использования, когда вы хотите выполнить операции поиска/замены, где вы хотите найти определенный шаблон и заменить его чем-то другим. Класс String уже имеет метод Replace (), но он хорош только для выполнения простого поиска. При использовании регулярных выражений можно использовать силу поиска регулярных выражений и даже использовать анализируемые группы как часть строки замены. Это звучит сложно? Не волнуйтесь, мы начнем с простого примера, а затем постепенно перейдем к более продвинутым вариантам использования.
Как в предыдущей статье все примеры подразумевают наличие важных пространств имен RegularExpressions таких, как это:
using System.Text.RegularExpressions;
Теперь давайте попробуем работать с заменой строк на основе регулярных выражений. Мы будем использовать метод Replace(), находящийся в классе Regex:
string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<[^>]+>");
string cleanString = regex.Replace(testString, "");
Console.WriteLine(cleanString);
В этом примере показан очень упрощенный подход к удалению HTML-тегов из строки. Мы сопоставляем все, что окружено набором угловых скобок (< & gt;), а затем используем метод Replace() для замены каждого вхождения пустой строки, в основном удаляя HTML-теги из тестовой строки.
Замена анализируемыми значениями
Но предположим, что вы на самом деле не хотите их удалять, но вместо этого вы хотите преобразовать теги во что-то, что не будет интерпретироваться браузером, например, заменив угловые скобки (<>) квадратными скобками ([]). Именно здесь регулярные выражения действительно показывают свою силу, потому что на самом деле это очень легко, как показано в этой слегка переписанной версии нашего предыдущего примера:
string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<([^>]+)>");
string cleanString = regex.Replace(testString, "[$1]");
Console.WriteLine(cleanString);
На самом деле я просто изменил две незначительные детали: я добавил набор скобок в регулярное выражение, чтобы создать группу анализа, по существу захватив значение между угловыми скобками в первую анализируемую группу. В методеReplace () я ссылаюсь на это, используя специальную нотацию$1 , что в основном означает только группу анализа номер 1. Теперь наши выходные данные будут выглядеть следующим образом:
[b]Hello, [i]world[/i][/b]
Именованные анализируемые группы
Конечно, вы можете делать точно то же самое, используя именованные анализируемые группы (обсуждаемые в предыдущей статье), как этот:
string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<(?<tagName>[^>]+)>");
string cleanString = regex.Replace(testString, "[${tagName}]");
Console.WriteLine(cleanString);
Используя именованные анализируемые группы, просто примените нотацию ${name-of-capture-group}.
Использование метода MatchEvaluator
Но если мы хотим еще больше контроля над тем, как значение заменяется? Для этого мы можем использовать параметр MatchEvaluator - это в основном просто ссылка (делегат) на метод, который будет вызываться каждый раз при замене, что позволяет изменять заменяемое значение перед его использованием. Давайте придерживаться примера HTML-тегов, который мы уже использовали пару раз, но на этот раз мы контролируем, какие HTML-теги используются. Вот полный пример:
using System;
using System.Text.RegularExpressions;
namespace RegexSearchReplaceMethod
{
class Program
{
static void Main(string[] args)
{
string testString = "<b>Hello, <i>world</i></b>";
Regex regex = new Regex("<(?<tagName>[^>]+)>");
string cleanString = regex.Replace(testString, ProcessHtmlTag);
Console.WriteLine(cleanString);
}
private static string ProcessHtmlTag(Match m)
{
string tagName = m.Groups["tagName"].Value;
string endTagPrefix = "";
if(tagName.StartsWith("/"))
{
endTagPrefix = "/";
tagName = tagName.Substring(1);
}
switch (tagName)
{
case "b":
tagName = "strong";
break;
case "i":
tagName = "em";
break;
}
return "<" + endTagPrefix + tagName.ToLower() + ">";
}
}
}
Первая часть примера выглядит точно так же, как и раньше, но вместо замены строки мы передаем ссылку на наш метод ProcessHtmlTag(). Как уже упоминалось, этот метод вызывается каждый раз, когда замена будет произведена, с матчем в качестве параметра. Это означает, что в нашем методе MatchEvaluator, у нас есть вся информация о матче, так что мы можем действовать соответственно. В этом случае мы используем эту возможность, чтобы сделать теги более семантическими, заменив тег bold (b) сильным тегом и тег italic (i) тегом с акцентом (em). Независимо от того, изменен тег или нет, мы превращаем его в Нижний регистр.
Использование параметра MatchEvaluator, очевидно, очень мощно, и это всего лишь простой пример того, что может быть достигнуто.
Резюме
Операции Поиска/Замены становятся очень полезными и даже больше того, когда вы используете регулярные выражения так что, когда вы пользуетесь параметром MatchEvaluator, возможности которого для манипуляций строками становятся почти безграничными.