На цьому уроці ми розглянемо з вами дуже потужний, широко використовуваний інструмент для обробки тексту - регулярні вирази.
Регулярний вираз - це якийсь шаблон, складений з символів і спецсимволов, який дозволяє знаходити підрядки відповідні цим шаблоном в інших рядках. Спецсимволов і різних правил їх комбінування є дуже багато, тому регулярні вирази можна навіть назвати таким собі окремою мовою програмування. Ті, хто користувався пошуком по файлах в 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 | Пробільний символ (пробіл, табуляція, переклад рядка і т. g.) | \ 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" |
Cимволи вибору
Позначення | Опис | Шаблон | Відповідність |
| | Працює як логічне «АБО» - відповідає першому і / або другому шаблоном | 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 ( "Ця електронна адреса захищена від спам-ботів. вам потрібно увімкнути JavaScript, щоб побачити її.")); // 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 ();
}
Домашнє завдання
1. Створіть програму, яка буде перевіряти коректність введення логіна. Коректним логіном буде рядок від 2-х до 10-ти символів, що містить тільки літери і цифри, і при цьому цифра не може бути першою.
2. Створіть фільтр мата. Метод буде приймати вихідну рядок, і повертати результат, де погані слова будуть замінені на «цензура». Обробіть хоча б одне таке слово, тільки передбачте безліч його форм. Якщо ви збираєтеся результат вашої роботи залишити тут, в коментарях, тоді фільтруйте будь-які інші слова, але не мати :)
PS. Не забудьте поділитися з друзями цією статтею за допомогою кнопок соціальних мереж.