Регулярные выражения в Си-шарп. Класс Regex
В этом уроке мы рассмотрим с вами очень мощный, широко используемый инструмент для обработки текста – регулярные выражения.
Регулярное выражение – это некий шаблон, составленный из символов и спецсимволов, который позволяет находить подстроки соответствующие этому шаблону в других строках. Спецсимволов и различных правил их комбинирования есть очень много, поэтому регулярные выражения можно даже назвать таким себе отдельным языком программирования. Те, кто пользовался поиском по файлам в Windows могут знать, что для того чтобы найти файлы только заданного расширения, задается шаблон типа «*.txt». Здесь «*» - спецсимвол, который означает любые имена файлов. Так вот регулярные выражения предоставляют подобный механизм.
Что можно делать, используя регулярные выражения
Регулярные выражения предоставляют массу возможностей, некоторые из них:
- заменять в строке все одинаковые слова другим словом, или удалять такие слова;
- выделять из строки необходимую часть. Например, из любой ссылки (http://mycsharp.ru/post/33/2013_10_19_virtualnye_metody_v_si-sharp_pereopredelenie_metodov.html) выделять только доменную часть (mycsharp.ru);
- проверять соответствует ли строка заданному шаблону. Например, проверять, правильно ли введен email, телефон т.д.;
- проверять, содержит ли строка заданную подстроку;
- извлекать из строки все вхождения подстрок, соответствующие шаблону регулярного выражения. Например, получить все даты из строки.
Начало работы с регулярными выражениями
Для того, чтобы работать с регулярными выражениями необходимо подключить в начале программы пространство имен using System.Text.RegularExpressions; В Си-шарп работу с регулярными выражениями предоставляет класс Regex. Создание регулярного выражения имеет следующий вид:
Regex myReg = new Regex([шаблон]);
Здесь [шаблон] – это строка содержащая символы и спецсимволы.
У Regex также есть и второй конструктор, который принимает дополнительный параметр – опции поиска. Это мы рассмотрим далее.
Приведу простой пример программы с использованием регулярных выражений:
static void Main(string[] args)
{
string data1 = "Петр, Андрей, Николай";
string data2 = "Петр, Андрей, Александр";
Regex myReg = new Regex("Николай"); // создание регулярного выражения
Console.WriteLine(myReg.IsMatch(data1)); // True
Console.WriteLine(myReg.IsMatch(data2)); // False
Console.ReadKey();
}
Здесь в качестве шаблона выступает однозначная строка "Николай". Дальше был использован метод IsMatch, который проверят, содержит ли заданная строка (data1, data2) подстроку соответствующую шаблону.
Методы класса Regex
Рассмотрим кратко методы для работы с регулярными выражениями:
IsMatch – проверяет содержит ли строка хотя бы одну подстроку соответствующую шаблону регулярного выражения. Работа этого метода показана в примере выше.
Match – возвращает первую подстроку, соответствующую шаблону, в виде объекта класса Match. Класс Match предоставляет различную информацию о подстроке – длину, индекс, само значение и другое.
static void Main(string[] args)
{
string data1 = "Петр, Андрей, Николай";
Regex myReg = new Regex("Николай");
Match match = myReg.Match(data1);
Console.WriteLine(match.Value); // "Николай"
Console.WriteLine(match.Index); // 14
Console.ReadKey();
}
Matches – возвращает все подстроки соответствующие шаблону в виде коллекции типа MatchCollection. Каждый элемент этой коллекции типа Match.
static void Main(string[] args)
{
string data1 = "Петр, Николай, Андрей, Николай";
Regex myReg = new Regex("Николай");
MatchCollection matches = myReg.Matches(data1);
Console.WriteLine(matches.Count); // 2
foreach (Match m in matches)
Console.WriteLine(m.Value); //вывод всех подстрок "Николай"
Console.ReadKey();
}
Replace – возвращает строку, в которой заменены все подстроки, соответствующие шаблону, новой строкой:
static void Main(string[] args)
{
string data1 = "Петр, Николай, Андрей, Николай";
Regex myReg = new Regex("Николай");
data1 = myReg.Replace(data1, "Максим");
Console.WriteLine(data1); //"Петр, Максим, Андрей, Максим"
Console.ReadKey();
}
Split - возвращает массив строк, полученный в результате разделения входящей строки в местах соответствия шаблону регулярного выражения:
static void Main(string[] args)
{
string data1 = "Петр,Николай,Андрей,Николай";
Regex myReg = new Regex(",");
string[] names = myReg.Split(data1); // массив имен
Console.ReadKey();
}
Специальные символы
В примерах выше рассматривались очень простые, однозначные регулярные выражения без использования спецсимволов. Спецсимволов существует достаточно много, их описание приведу ниже в таблицах:
Классы символов
Обозначение |
Описание |
Шаблон |
Соответствие |
[группа_символов] |
Любой из перечисленных в скобках символов. Используя тире можно указать диапазон символов, например, [a-f] - то же самое, что [abcdef] |
[abc] |
«a» в «and» |
[^группа_символов] |
Любой символ, кроме перечисленных в скобках |
[^abc] |
«n», «d» в «and» |
\d |
Цифра. Эквивалентно [0-9] |
\d |
«1» в «data1» |
\D |
Любой символ, кроме цифр. Эквивалентно [^0-9] |
\D |
«y» в «2014y» |
\w |
Цифра, буква (латинский алфавит) или знак подчеркивания. Эквивалентно [0-9a-zA-Z_] |
\w |
«1», «5», «с» в «1.5с» |
\W |
Любой символ, кроме цифр, букв (латинский алфавит) и знака подчеркивания. Эквивалентно [^0-9a-zA-Z_] |
\W |
«.» в «1.5с» |
\s |
Пробельный символ (пробел, табуляция, перевод строки и т. п.) |
\s |
« » в «c sharp» |
\S |
Любой символ, кроме пробельных |
\S |
«c» «s» «h» «a» «r» «p» в «c sharp» |
. |
Любой символ, кроме перевода строки. Для поиска любого символа, включая перевод строки, можно использовать конструкцию [\s\S] |
c.harp |
«csharp» в «mycsharp» |
Символы повторения
Обозначение |
Описание |
Шаблон |
Соответствие |
* |
Соответствует предыдущему элементу ноль или более раз |
\d*. |
«a», «1b», «23c » в «a1b23c» |
+ |
Соответствует предыдущему элементу один или более раз |
\d+. |
«1b», «23c » в «a1b23c» |
? |
Соответствует предыдущему элементу ноль или один раз |
\d?\D |
«a», «1b», «3с» в «a1b23c» |
{n} |
Соответствует предыдущему элементу, который повторяется ровно n раз |
\d{2} |
«43», «54», «82» в «2,43,546,82» |
{n,} |
Соответствует предыдущему элементу, который повторяется минимум n раз |
\d{2,} |
«43», «546», «82» в «2,43,546,82» |
{n,m} |
Соответствует предыдущему элементу, который повторяется минимум n раз и максимум m |
\d{2,} |
«43», «546», «821» в «2,43,546,8212» |
Символы привязки
Обозначение |
Описание |
Шаблон |
Соответствие |
^ |
Соответствие должно находиться в начале строки |
^\d{2} |
«32» в «32,43,54» |
$ |
Соответствие должно находиться в конце строки или до символа \n при многострочном поиске |
\d{2}$ |
«54» в «32,43,54» |
\b |
Соответствие должно находиться на границе алфавитно-цифрового символа (\w) и не алфавитно-цифрового (\W) |
\b\d{2} |
«32», «54» в «32 a43 54» |
\B |
Соответствие не должно находиться на границе |
\B\d{2} |
«43» в «32 a43 54» |
\G |
Соответствие должно находиться на позиции конца предыдущего соответствия |
\G\d |
«3», «2», «4» в «324.758» |
Символы выбора
Обозначение |
Описание |
Шаблон |
Соответствие |
| |
Работает как логическое «ИЛИ» - соответствует первому и/или второму шаблону |
one|two |
«one», «two» в «one two three» |
(группа_символов) |
Группирует набор символов в единое целое для которого дальше могут использоваться + * ? и т.д. Каждой такой группе назначается порядковый номер слева направо начиная с 1. По этому номеру можно ссылаться на группу \номер_группы |
(one)\1 |
«oneone» в «oneone onetwoone» |
(?:группа_символов) |
Та же группировка только без назначения номера группы |
(?:one){2} |
«oneone» в «oneone onetwoone» |
Другие символы
Обозначение |
Описание |
Шаблон |
Соответствие |
\t |
Символ табуляции |
\t |
|
\v |
Символ вертикальной табуляции |
\v |
|
\r |
Символ возврата каретки |
\r |
|
\n |
Символ перевода строки |
\n |
|
\f |
Символ перевода страницы |
\f |
|
\ |
Символ, который позволяет экранировать специальные символы, чтобы те воспринимались буквально. Например, чтобы было соответствие символу звёздочки, шаблон будет выглядеть так \* |
\d\.\d |
«1.1», «1.2» в «1.1 1.2» |
В этих таблицах представлены далеко не все элементы языка регулярных выражений, но их вполне достаточно для больших возможностей.
Приведу пример программы, которая проверят корректность электронного адреса (шаблон тот же, что и на странице регистрации на этом сайте):
static void Main(string[] args)
{
Regex myReg = new Regex(@"[A-Za-z]+[\.A-Za-z0-9_-]*[A-Za-z0-9]+@[A-Za-z]+\.[A-Za-z]+");
Console.WriteLine(myReg.IsMatch("email@email.com")); // True
Console.WriteLine(myReg.IsMatch("email@email")); // False
Console.WriteLine(myReg.IsMatch("@email.com")); // False
Console.ReadKey();
}
Здесь перед началом строки регулярного выражения стоит символ «@» который указывает комплятору воспринимать все символы буквально. Это необходимо, чтобы корректно воспринимался символ «\».
Параметры поиска
Здесь мы поговорим о втором конструкторе Regex, который принимает в качестве второго аргумента значение перечисления RegexOptions. В этом перечисление есть следующие значения:
IgnoreCase – игнорирование регистра при поиске. Находит соответствия независимо прописными или строчными буквами в строке написано слово;
RightToLeft – поиск будет выполнен справа налево, а не слева направо;
Multiline – многострочный режим поиска. Меняет работу спецсимволов «^» и «$» так, что они соответствуют началу и концу каждой строки, а не только началу и концу целой строки;
Singleline – однострочный режим поиска;
CultureInvariant - игнорирование национальных установок строки;
ExplicitCapture – обеспечивается поиск только буквальных соответствий;
Compiled – регулярное выражение компилируется в сборку, что делает более быстрым его исполнение но увеличивает время запуска;
IgnorePatternWhitespace – игнорирует в шаблоне все неэкранированные пробелы. С этим параметром шаблон «a b» будет аналогичным шаблону «ab»;
None – использовать поиск по умолчанию.
Пример программы с использованием параметра поиска (игнорирование регистра):
static void Main(string[] args)
{
string data = "nikolay, sergey, oleg";
Regex myRegIgnoreCase = new Regex(@"Sergey", RegexOptions.IgnoreCase);
Regex myReg = new Regex(@"Sergey");
Console.WriteLine(myRegIgnoreCase.IsMatch(data)); // True
Console.WriteLine(myReg.IsMatch(data)); // False
Console.ReadKey();
}
Если необходимо установить несколько параметров, тогда они разделяются оператором поразрядного «ИЛИ» - «|»
Regex myReg = new Regex(@"Sergey", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
Приведу еще один пример использования регулярных выражений. Создадим метод, который будет принимать ссылку, а возвращать только доменное имя:
public static string GetDomain(string url)
{
Regex re = new Regex("http://", RegexOptions.IgnoreCase);
url = re.Replace(url, ""); // удаляем часть http://
Regex reWww = new Regex(@"www\.", RegexOptions.IgnoreCase);
url = reWww.Replace(url, ""); //удаляем часть www.
int end = url.IndexOf("/");
if (end != -1)
url = url.Substring(0, end);
return url;
}
static void Main(string[] args)
{
string url1 = "http://mycsharp.ru/post/33/2013_10_19_virtualnye_metody_v_si-sharp_pereopredelenie_metodov.html";
string url2 = "http://www.mycsharp.ru/post/33/2013_10_19_virtualnye_metody_v_si-sharp_pereopredelenie_metodov.html";
Console.WriteLine(GetDomain(url1)); // mycsharp.ru
Console.WriteLine(GetDomain(url2)); // mycsharp.ru
Console.ReadKey();
}