| Украина, Луганская обл., г. Рубежное |
Регулярные выражения
Стандартный класс string позволяет выполнять над строками различные операции, в том числе поиск, замену, вставку и удаление подстрок. Тем не менее, есть классы задач по обработке символьной информации, где стандартных возможностей явно не хватает. Чтобы облегчить решение подобных задач, в Net Framework встроен более мощный аппарат работы со строками, основанный на регулярных выражениях.
Регулярные выражения предназначены для обработки текстовой информации и обеспечивают:
- Эффективный поиск в тексте по заданному шаблону;
- Редактирование текста;
- Формирование итоговых отчетов по результатам работы с текстом.
Подробно рассмотрим первые два аспекта применения регулярных выражений.
Метасимволы в регулярных выражениях
Регулярное выражение - это шаблон, по которому выполняется поиск соответствующего фрагмента текста. Язык описания регулярных выражений состоит из символов двух видов: обычных символов и метасимволов. Обычный символ представляет в выражении сам себя, а метасимвол - некоторый класс символов.
Рассмотрим наиболее употребительные метасимволы:
Кроме метасимволов, обозначающие классы символов, могут применяться уточняющие метасимволы:
| Уточняющие символы | Описание |
|---|---|
| ^ | Фрагмент, совпадающий с регулярными выражениями, следует искать только в начале строки |
| $ | Фрагмент, совпадающий с регулярными выражениями, следует искать только в конце строки |
| \А | Фрагмент, совпадающий с регулярными выражениями, следует искать только в начале многострочной строки |
| \Z | Фрагмент, совпадающий с регулярными выражениями, следует искать только в конце многострочной строки |
| \b | Фрагмент, совпадающий с регулярными выражениями, начинается или заканчивается на границе слова, т.е. между символами, соответствующими метасимволам \w и \W |
| \B | Фрагмент, совпадающий с регулярными выражениями, не должен встречаться на границе слов |
В регулярных выражениях часто используются повторители - метасимволы, которые располагаются непосредственно после обычного символа или группы символов и задают количество его повторений в выражении.
| Повторители | Описание | Пример |
|---|---|---|
| * | Ноль или более повторений предыдущего элемента | Выражение ca*t соответствует фрагментам: ct, cat, caat, caaat и т.д. |
| + | Одно или более повторений предыдущего элемента | Выражение ca+t соответствует фрагментам: cat, caat, caaat и т.д. |
| ? | Не более одного повторения предыдущего элемента | Выражение ca?t соответствует фрагментам: ct, cat. |
| {n} | Ровно n повторений предыдущего элемента | Выражение ca{3}t соответствует фрагменту: cаааt. Выражение (cat){2} соответствует фрагменту: c а tcat. |
| {n,} | По крайней мере n повторений предыдущего элемента | Выражение ca{3, }t соответствует фрагментам: c ааа t, caaaat, caaaaaaat и т.д. Выражение (cat){2, } соответствует фрагментам: catcat, catcatcat и т.д. |
| {n, m} | От n до m повторений предыдущего элемента | Выражение ca{2, 4}t соответствует фрагментам: c аа t, caaat, caaaat. |
Регулярное выражение записывается в виде строкового литерала, причем перед строкой необходимо ставить символ @, который говорит о том, что строку нужно будет рассматривать и в том случае, если она будет занимать несколько строчек на экране. Однако символ @ можно не ставить, если в качестве шаблона используется шаблон без метасимволов.
Примеры регулярных выражений:
- слово rus -
@"rus" или "rus"
- номер телефона в формате xxx-xx-xx - @"\d\d\d-\d\d-\d\d" или @"\d{3}(-\d\d){2}"
- номер автомобиля - @"[A-Z]\d{3}[A-Z]{2}\d{2,3}RUS"
- дате в формате дд.мм.гг или дд.мм.гггг
- времени в формате чч.мм или чч:мм
- целому числу (со знаком и без)
- вещественному числу (со знаком и без, с дробной частью и без, с целой частью и без)
Поиск в тексте по шаблону
Пространство имен библиотеки базовых классов System.Text.RegularExpressions содержит все объекты платформы .NET Framework, имеющие отношение к регулярным выражениям. Важнейшим классом, поддерживающим регулярные выражения, является класс Regex, который представляет неизменяемые откомпилированные регулярные выражения. Для описания регулярного выражения в классе определено несколько перегруженных конструкторов:
- Regex() - создает пустое выражение;
- Regex(String) - создает заданное выражение;
- Regex(String, RegexOptions) - создает заданное выражение и задает параметры для его обработки с помощью элементов перечисления RegexOptions (например, различать или нет прописные и строчные буквы).
Поиск фрагментов строки, соответствующих заданному выражению, выполняется с помощью методов IsMatch, Match, Matches класса Regex.
Метод IsMatch возвращает true, если фрагмент, соответствующий выражению, в заданной строке найден, и false в противном случае. Например, попытаемся определить, встречается ли в заданном тексте слово собака:
static void Main()
{
Regex r = new Regex("собака",RegexOptions.IgnoreCase);
string text1 = "Кот в доме, собака в конуре.";
string text2 = "Котик в доме, собачка в конуре.";
Console.WriteLine(r.IsMatch(text1));
Console.WriteLine(r.IsMatch(text2));
}Замечание. RegexOptions.IgnoreCase - означает, что регулярное выражение применяется без учета регистра символов.
Можно использовать конструкцию выбора из нескольких элементов. Варианты выбора перечисляются через вертикальную черту. Например, попытаемся определить, встречается ли в заданном тексте слов собака или кот:
static void Main(string[] args)
{
Regex r = new Regex("собака|кот",RegexOptions.IgnoreCase);
string text1 = "Кот в доме, собака в конуре.";
string text2 = "Котик в доме, собачка в конуре.";
Console.WriteLine(r.IsMatch(text1));
Console.WriteLine(r.IsMatch(text2));
}Попытаемся определить, есть ли в заданных строках номера телефона в формате xx-xx-xx или xxx-xx-xx:
static void Main()
{
Regex r = new Regex(@"\d{2,3}(-\d\d){2}");
string text1 = "tel:123-45-67";
string text2 = "tel:no";
string text3 = "tel:12-34-56";
Console.WriteLine(r.IsMatch(text1));
Console.WriteLine(r.IsMatch(text2));
Console.WriteLine(r.IsMatch(text3));
}Метод Match класса Regex не просто определяет, содержится ли текст, соответствующий шаблону, а возвращает объект класса Match - последовательность фрагментов текста, совпавших с шаблоном. Следующий пример позволяет найти все номера телефонов в указанном фрагменте текста:
static void Main()
{
Regex r = new Regex(@"\d{2,3}(-\d\d){2}");
string text = @"Контакты в Москве tel:123-45-67, 123-34-56; fax:123-56-45
Контакты в Саратове tel:12-34-56; fax:12-56-45";
Match tel = r.Match(text);
while (tel.Success)
{
Console.WriteLine(tel);
tel = tel.NextMatch();
}
}Следующий пример позволяет подсчитать сумму целых чисел, встречающихся в тексте:
static void Main()
{
Regex r = new Regex(@"[-+]?\d+");
string text = @"5*10=50 -80/40=-2";
Match teg = r.Match(text);
int sum = 0;
while (teg.Success)
{
Console.WriteLine(teg);
sum += int.Parse(teg.ToString());
teg = teg.NextMatch();
}
Console.WriteLine("sum=" + sum);
}Метод Matches класса Regex возвращает объект класса MatchCollection - коллекцию всех фрагментов заданной строки, совпавших с шаблоном. При этом метод Matches многократно запускает метод Match, каждый раз начиная поиск с того места, на котором закончился предыдущий поиск.
static void Main(string[] args)
{
string text = @"5*10=50 -80/40=-2";
Regex theReg = new Regex(@"[-+]?\d+");
MatchCollection theMatches = theReg.Matches(text);
foreach (Match theMatch in theMatches)
{
Console.Write("{0} ", theMatch.ToString());
}
Console.WriteLine();
}
}Редактирование текста
Регулярные выражения могут эффективно использоваться для редактирования текста. Например, метод Replace класса Regex позволяет выполнять замену одного фрагмента текста другим или удаление фрагментов текста:
Пример 1. Изменение номеров телефонов:
static void Main(string[] args)
{
string text = @"Контакты в Москве tel:123-45-67, 123-34-56; fax:123-56-45.
Контакты в Саратове tel:12-34-56; fax:11-56-45";
Console.WriteLine("Старые данные\n"+text);
string newText=Regex.Replace(text, "123-", "890-");
Console.WriteLine("Новые данные\n" + newText);
}Пример 2. Удаление всех номеров телефонов из текста:
static void Main()
{
string text = @"Контакты в Москве tel:123-45-67, 123-34-56; fax:123-56-45.
Контакты в Саратове tel:12-34-56; fax:12-56-45";
Console.WriteLine("Старые данные\n"+text);
string newText=Regex.Replace(text, @"\d{2,3}(-\d\d){2}", "");
Console.WriteLine("Новые данные\n" + newText);
}
}Пример 3. Разбиение исходного текста на фрагменты:
static void Main()
{
string text = @"Контакты в Москве tel:123-45-67, 123-34-56; fax:123-56-45.
Контакты в Саратове tel:12-34-56; fax:12-56-45";
string []newText=Regex.Split(text,"[ ,.:;]+");
foreach( string a in newText)
Console.WriteLine(a);
}