Содержание:
Теория
- Регулярные выражения позволяют осуществлять поиск по шаблону в тексте.
- Строка шаблона включает символьные классы.
Символьные классы — символы (латинские буквы) с впереди стоящим слешем \
, которые в шаблоне несут смысловую нагрузку: на их месте должно или может находиться что-то конкретное.
using System.Text.RegularExpressions; // пространство имен для работы с регулярными выражениями |
классы платформы .NET для работы с регулярными выражениями:
Статические методы класса Regex
1. Match Regex.Match(s,pattern) 2. bool Regex.IsMatch(s,pattern) 3. MatchCollection Regex.Matches(s,pattern) 4. string Regex.Replace(s,pattern,replace_s) 5. string[] Regex.Split(s,pattern)
Методы для многократного использования одного шаблона
var r = new Regex(pattern); r.Match(s) r.IsMatch(s) r.Matches(s) r.Replace(s,replace_s) |
Переменные класса Match и их свойства
string s = "one two three four two five alice two"; Match m = Regex.Match(s, "two"); //1. m.Success Console.WriteLine(m.Success); // True //2. m.Value Console.WriteLine(m.Value); // two //3. m.Index Console.WriteLine(m.Index); // 4 //4. m.Length Console.WriteLine(m.Length); // 2 //5. m.NextMatch().Index Console.WriteLine(m.NextMatch().Index); // 19 |
Класс MatchCollection – свойство Count
.
foreach (var m in MatchCollection) // here m is Match type |
Пример 1:
//... // подключение области имен RegularExpressions using System.Text.RegularExpressions; //... // просто какая-то строка string s = " one two three four two five alice two"; var m = Regex.Match(s, "two"); // шаблон // методы: Console.WriteLine(m.Index); // вывод: 5 Console.WriteLine(m.NextMatch().Index); // вывод: 20 Console.WriteLine(m.NextMatch().NextMatch().Index); // вывод: 35 |
Пример 2:
// подключение области имен RegularExpressions using System.Text.RegularExpressions; //... // просто какая-то строка string s = " one two three four two five alice two"; // используем цикл для прохода по строке foreach (Match m in Regex.Matches(s, "two")) { Console.Write(m.Index + " "); // вывод: 5 20 35 } |
Пример 3:
// подключение области имен RegularExpressions using System.Text.RegularExpressions; //... // просто какая-то строка string s = " one two three four two five alice two"; var ss = s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var ss = Regex.Split(s, " +"); Console.WriteLine(ss); |
Примеры регулярных выражений
Текст для поиска | шаблон поиска |
---|---|
asdasdasdhelloasdasdasd | @“hello” |
hello | @“^hello$” |
asdasdelholasdasdasd
asdasdeeeeeedfgdgdg |
@“[hello]” or @“[hello]{6}” |
SdfuiyuiewrR345 | @“[a-zA-Z0-9]” or @“\w” |
452341 | @“[0-9]” or @“\d” |
jsdf8H?& | @“.” |
Example:
string s = "asdasdasdhelloasdasdasd"; Match m = Regex.Match(s, @"hello"); Console.WriteLine(m.Success); // True m = Regex.Match(s, @"^hello"); Console.WriteLine(m.Success); // False |
Метасимволы и экранирование
Следующие метасимволы имеют специальное назначение в регулярных выражениях, поэтому не могут быть просто так использованы в тексте:
( ) { } [ ] ? * + - ^ $ . | \
Если необходимо прямо в тексте использовать данные символа (например, символ точку (.
)), то необходимо выполнить, так сказать, «экранирование». Это можно сделать расположив обратный слэш (\
) перед самим символом.
Конечно, \
также является escape-символом для строковых литералов в C#. Чтобы получить литерал \
, необходимо удвоить его в строке (т.e. «\\
» — это строка с одним символом). В качестве альтернативы, можно использовать также так называемые дословные строковые литералы, начинающиеся с символа @
; в таком случае использовать \
в качестве экранизации не нужно. Т.о. следующие две строки абсолютно одинаковы:
"c:\\Docs\\Source\\a.txt" @"c:\Docs\Source\a.txt" |
Кванторы
Подстановочные знаки | объяснение | Пример | Подходящий текст |
---|---|---|---|
\d | цифра 0 до 9 | file_\d\d | file_25 |
\w | Символ Unicode, цифра | \w—\w\w\w |
A-b_1 |
\s | «пробельный символ»: любой пробельный символ Unicode | a\sb\sc | a b c |
\D | Символ, не являющийся цифрой | \D\D\D | ABC |
\W | Один символ, который не является символом из набора \w | \W\W\W\W\W | *-+=) |
\S | Один символ, который не является пробельным символом из набора \s | \S\S\S\S | Yoyo |
\b | Границы слов | ||
\B | Обратное \b | ||
. | Любой символ, кроме разрыва строки | a.c | abc |
\. | Точка (специальный символ: должен быть экранирован слэшем \) | a\.c | a.c |
\ | Экранирует специальный символ | \[\{\(\)\}\] | [{()}] |
Квантор | Пояснение | Пример | Подходящий текст |
---|---|---|---|
+ | Один или более | Version \w-\w+ | Version A-b1_1 |
{3} | Ровно три раза | \D{3} | ABC |
{2,4} | Два или четыре раза | \d{2,4} | 156 |
{3,} | три раза или более | \w{3,} | regex_tutorial |
* | ноль или более раз | A*B*C* | AAACC |
? | один раз или нисколько | plurals? | plural |
[…] | Любой символ в фигурных скобках | ||
| | Символ перед | ИЛИ после него |
cat|dog | sdfcatsdf |
Директивы нулевой длины | |||
^ | Поиск с начала строки | ||
$ | Поиск до конца строки | ||
\b | положение на границе слова |
Замены с помощью регулярных выражений
string s = "10+2=12"; s = Regex.Replace(s, @"\d+", "<$0>"); // <10>+<2>=<12> s = Regex.Replace(s, @"\d+", m => (int.Parse(m.Value) * 2).ToString()); // 20+4=24 |
Примеры
Пример 1:
Для следующего примера подходят слова, начинающиеся с ‘S’
using System; using System.Text.RegularExpressions; namespace RegExApplication { class Program { private static void showMatch(string text, string expr) { Console.WriteLine("The Expression: " + expr); MatchCollection mc = Regex.Matches(text, expr); foreach (Match m in mc) { Console.WriteLine(m); } } static void Main(string[] args) { string str = "A Thousand Splendid Suns"; Console.WriteLine("В следующем примере подходят слова, начинающиеся с 'S': "); showMatch(str, @"\bS\S*"); Console.ReadKey(); } } } |
Результат:
подходят слова, начинающиеся с 'S': Выражение: \bS\S* Splendid Suns
Пример 2:
В следующем примере подойдут слова, начинающиеся с ‘m’ и заканчивающиеся ‘e’
using System; using System.Text.RegularExpressions; namespace RegExApplication { class Program { private static void showMatch(string text, string expr) { Console.WriteLine("Выражение: " + expr); MatchCollection mc = Regex.Matches(text, expr); foreach (Match m in mc) { Console.WriteLine(m); } } static void Main(string[] args) { string str = "make maze and manage to measure it"; Console.WriteLine("подойдут слова, начинающиеся с 'm' и заканчивающиеся 'e':"); showMatch(str, @"\bm\S*e\b"); Console.ReadKey(); } } } |
Результат:
подойдут слова, начинающиеся с 'm' и заканчивающиеся 'e': Выражение: \bm\S*e\b make maze manage measure
Пример 3:
Пример удаляет лишние пробелы
Live Demo using System; using System.Text.RegularExpressions; namespace RegExApplication { class Program { static void Main(string[] args) { string input = "Hello World "; string pattern = "\\s+"; string replacement = " "; Regex rgx = new Regex(pattern); string result = rgx.Replace(input, replacement); Console.WriteLine("Исходная строка: {0}", input); Console.WriteLine("Результат: {0}", result); Console.ReadKey(); } } } |
Результат:
Исходная строка: Hello World Результат: Hello World
Задания и лабораторные работы
Выполнить: Запрашивается номер телефона. Проверьте, является ли введенный номер ростовским номером федерального формата (номер федерального формата:
+7 (863) 3**-**-**
или +7 (863) 2**-**-**
). Где *
означает цифру. Напишите функцию, возвращающую логическое (Boolean) значение (true
или false
).
Указание 1: Строка должна содержать только номер телефона, а регулярное выражение должно содержать при этом кванторы ^
и $
.
Указание 2: Так как +
, (
и )
символы имеют специальное предназначение в регулярных выражениях, они должны быть экранированы, т.е. перед ними должен быть установлен обратный слэш: \+
.
Указание 3: Для того, чтобы удостовериться, что программа работает корректно, необходимо сделать 3 или 4 теста, используя метод Debug.Assert
.
Примерный результат:
Тесты пройдены Введите номер телефона: +7 (863) 323-22-12 True +++++++++++++++++ Тесты пройдены Введите номер телефона: 7 (863) 323-22-12 False +++++++++++++++++ Тесты пройдены Введите номер телефона: +7 (8634) 323-22-12 False
[Название проекта: Lesson_12Lab1
, название файла L12Lab1.cs
]
✍ Алгоритм:
- Создайте проект и переименуйте файл.
- Установите курсор в начало кода, после подключения пространств имен и классов. Включите следующее пространство имен для использования методов регулярных выражений:
- Для выполнения автоматических тестов необходимо добавить еще один класс. Поместите следующий код после предыдущего:
- Давайте последовательно, символ за символом, рассмотрим формат номера телефона:
+7 (863) 3**-**-**
or+7 (863) 2**-**-**
+
: это специальный символ, это означает, что для его использования в нашем шаблоне нам нужно поместить\
для экранизации. Таким образом имеем:
\+
7
далее идет определенная цифра, то есть нет необходимости использовать квантор или специальный символ. Имеем:пробел
: Для отображения пробела есть специальный символ —\s
; имеем:(
: это специальный символ, который необходимо экранировать префиксом\
:863
: это определенные цифры, т.е. имеем:)
: скобку необходимо экранировать символом\
:пробел
: Для пробела используем подстановочный знак\s
:3 или 2
: Для выбора одного из вариантов применяем квантор[]
:любая цифра
: За цифры отвечает подстановочный знак\d
. Для трех цифр подряд (в формате имеем ***) будем использовать квантор фигурные скобки (()
):-
: это конкретный символ, значит, не используем ни квантор, ни подстановочный знак:любая цифра
: Для любой цифры используем подстановочный знак\d
. Для того, чтобы указать, что цифры будет две, будем использовать фигурные скобки с указанием количества:-
: конкретный символ:любой символ
:- В задании у нас есть указание, что текст не должен содержать ничего другого, кроме самого телефона. То есть необходимо добавить кванторы начала и конца строки (
^
и$
): - Создайте функцию
IsPhonenumber()
с одним параметром — вводимой строкой (телефоном); функция возвращает значение типа boolean —true
илиfalse
: - Внутри функции будем использовать статический метод
IsMatch
класса Regex с двумя параметрами: вводимая строка и регулярное выражение. - В функции
Main
вызовите методIsPhonenumber
. Это необходимо сделать, используя автоматический тест: использовать методAssert
классаDebug
.Assert(bool)
метод проверяет предоставленное ему сравнение; если сравнение равноfalse
, он отображает окно сообщения, в котором указывается стек вызовов. Если сравнениеtrue
, сообщение об ошибке не отправляется, и окно сообщения не отображается. - Давайте сначала в автоматическом тесте вызовем наш метод с неверным форматом телефона. Чтобы получить результат
true
будем использовать знак отрицания!
: - Запустите приложение. Никакого сообщения не появилось. Это означает, что введенный в автоматическом тесте телефон действительно был с неправильным форматом (мы добавили отрицание
!
). - Затем создадим автоматический тест с верным форматом телефона:
- Затем, опять неверным форматом:
- Запустите приложение. Должно быть только оповещение о том, что тесты пройдены.
- Теперь попросим пользователя ввести как-либо номер телефона:
- Запустите приложение и проверьте правильность его исполнения.
- Добавьте комментарий с текстом задания и отправьте главный файл на проверку.
//...
using System.Text.RegularExpressions;
//...
//... using System.Text.RegularExpressions; using System.Diagnostics; //...
\+7
\+7\s
\+7\s\(
\+7\s\(863
\+7\s\(863\)
\+7\s\(863\)\s
\+7\s\(863\)\s[32]
\+7\s\(863\)\s\d{3}
\+7\s\(863\)\s\d{3}-
\+7\s\(863\)\s\d{3}-\d{2}
\+7\s\(863\)\s\d{3}-\d{2}-
\+7\s\(863\)\s\d{3}-\d{2}-\d{2}
^\+7\s\(863\)\s\d{3}-\d{2}-\d{2}$
static IsPhonenumber(string number) { ... }
IsMatch
логического типа определяет соответствует ли строка регулярному выражению. Метод возвращает true
или false
.static bool IsPhonenumber(string stringNumber) { return Regex.IsMatch(stringNumber, @"^\+7\s\(863\)\s\d{3}-\d{2}-\d{2}$"); }
Debug.Assert(!IsPhonenumber("+7 (800) 231-45-84"));
Debug.Assert(IsPhonenumber("+7 (863) 231-45-84"));
Debug.Assert(!IsPhonenumber("+7 (8631) 21-45-84"));
После всех тестов необходимо добавить оповещение, что все тесты пройдены:
Console.WriteLine("Тесты пройдены");
Console.WriteLine("Введите номер телефона:"); string number = Console.ReadLine(); Console.WriteLine(IsPhonenumber(number));
Выполнить: Запросите у пользователя ввести дату. Проверьте, имеет ли введенная дата верный формат: dd-mm-yyyy
(если одно из составных чисел dd
или mm
или yyyy
имеет только одну цифру, то необходимо доставлять префикс 0
: например, 02
)
Указание: Создайте функцию для проверки вводимого текста. В главной программе создайте три или четыре автоматических теста для проверки корректности работы созданной функции. Используйте метод Debug.Assert
.
Примерный вывод:
Тесты пройдены корректно Пожалуйста, введите дату: 12/03/1975 Формат даты неверный +++++++++ Тесты пройдены корректно Пожалуйста, введите дату: 2-3-1975 Формат даты неверный +++++++++ Тесты пройдены корректно Пожалуйста, введите дату: 12-03-1975 Формат даты верный +++++++++
[Название проекта: Lesson_12Task1
, название файла L12Task1.cs
]
Выполнить: Создайте функцию, которая подсчитывает количество почтовых индексов внутри строки (известно, что почтовый индекс содержит 6 подряд идущих цифр).
Указание 1: Создайте метод для подсчета индексов.
Указание 2: Для подсчета используйте метод Count
класса Regex
(информацию можно найти в справке языка C#).
Указание 3: Для проверки корректности работы созданной функции создайте 3 или 4 автоматических теста. Используйте метод Debug.Assert
.
Примерный вывод:
Тесты пройдены Для строки '123: почтовый индекс 367824 севернее, чем 123712' строка содержит 2 почтовых индекса
[Название проекта: Lesson_12Lab2
, название файла L12Lab2.cs
]
✍ Алгоритм:
- Создайте новый проект.
- Для использования методов регулярных выражений подключите необходимое пространство имен:
- Для возможности добавления автоматических тестов подключите класс
Diagnostics
: - Создайте функцию
CountZip
с одним аргументом — введенной строкой. Функция должна возвращать целочисленное значение — количество вхождений почтовых индексов: - Теперь создадим шаблон регулярного выражения.
- Сначала укажем границу слова (
\b
обозначает начало и конец слова):
"\b...\b"
- Сначала укажем границу слова (
- Почтовый индекс состоит из 6 цифр подряд. Для цифр будем использовать подстановочный знак
\d
, для обозначение того, что их шесть используем квантор{6}
: - Таким образом, имеем шаблон:
- Для того чтобы посчитать сколько именно раз шаблон регулярного выражения будет «входить» в строку будет использовать стандартный метод
Matches
. - Расположите следующий код в теле созданной функции:
- Внутри функции
Main
вызовите функциюCountZip
. Но сначала будем использовать автоматические тесты для проверки корректности работы созданной функции: используем методAssert
классаDebug
.Assert(bool)
проверяет условие; в случае если оно ложно, отображается сообщение с ошибкой. - В автоматическом тесте сначала вызовем функцию со строкой с двумя почтовыми индексами. Чтобы в качестве результата получить true нужно в условии указать, что функция вернет значение 2:
- Запустите приложение. В случае корректности работы функции никакого сообщения появиться не должно было.
- Создадим тест с вызовом функции со строкой без почтового индекса. Затем выведем оповещение, что тесты выполнены:
- Запустите приложение.
- Ну и наконец вызовем функцию для конкретной строки. Создадим строковую переменную и присвоим ей значение:
- Запустите приложение.
- Добавьте комментарий с заданием и отправьте файл на проверку.
//...
using System.Text.RegularExpressions;
//...
//...
using System.Text.RegularExpressions;
using System.Diagnostics;
//...
static CountZip(string zip) { ... }
"\b\d{6}\b"
\b начало слова \d{6} любые цифры, 6 подряд \b конец слова
Matches(String)
ищет все вхождения регулярного выражения в указанной строке. Метод возвращает коллекцию объектов Match вхождений. Если вхождений не обнаружено, метод возвратит пустую коллекцию.var m = Regex.Matches(zip, @"\b\d{6}\b"); return m.Count;
Debug.Assert(CountZip("344113 34116 15 152566 14254124 12515 hello") == 2);
Debug.Assert(CountZip("hello") == 0); Console.WriteLine("Тесты пройдены"); |
string zipCode = "123: почтовый индекс 367824 севернее, чем 123712"; Console.WriteLine($"строка содержит {CountZip(zipCode)} почтовых индекса"); |
Выполнить: Создайте функцию, подсчитывающую количество смайликов в переданной строке.
Смайликом читаются следующие варианты:
;
(точка с запятой) либо :
(двоеточие), встречающиеся ровно один раз;-
(дефис) может встретиться один раз или сколько угодно раз (даже ноль раз);(
,)
, [
,]
;
Указание 1: Создайте функцию для подсчета смайликов.
Указание 2: Используйте метод Count
класса Regex
.
Указание 3: Добавьте 3-4 автоматических теста для проверки корректности работы функции. ИспользуйтеDebug.Assert
.
Примерный вывод:
Тесты пройдены Для строки 'Привет папа :) Я скучаю :-(' имеем 2 смайлика
[Название проекта: Lesson_12Task2
, файл L12Task2.cs
]
Выполнить: Создайте функцию, удаляющую лишние пробелы в строке (пробелов может быть несколько подряд). Необходимо использовать метод
Replace
.
Указание 1: Создайте метод с тремя аргументами: исходная строка, шаблон регулярного выражения, и строка в которой замены. Значение по умолчанию для строки замены должен быть просто пробельный символ " "
(т.е. пробел должен быть вставлен вместо любого количества подряд идущих пробелов).
Указание 2: Использовать метод Replace
класса Regex
.
Указание 3: Создайте 3-4 автоматических теста для проверки правильности работы функции.
Примерный вывод:
Тесты пройдены Исходная строка: 'Hello World ' Результирующая строка: 'Hello World '
[Название проекта: Lesson_12Lab3
, название файла L12Lab3.cs
]
✍ Алгоритм:
- Создайте новый проект.
- Подключите необходимое пространство имен для работы с регулярными выражениями:
- Для добавления автоматических тестов подключите пространство имен
Diagnostics
: - Создайте функцию
ReplaceSpaces
с тремя аргументами — исходная строка, шаблон регулярного выражения и строка замены. Функция должна возвращать значение типа string — результирующую строку: - Создадим шаблон регулярного выражения.
Для использования пробельного знака в шаблоне есть специальный подстановочный знак\s
. Так как в строке может находиться несколько пробелов подряд, то будем использовать квантор+
, который обозначает одно или несколько вхождений: - В функции
Main
присвойте шаблон переменной с именемpattern
: - Затем создайте переменную для хранения строки замены; несколько пробелов подряд будут заменены на
" "
— один пробел: - Необходимо использовать метод
Replace
. - Расположите код в теле созданной функции:
- Перейдите в функцию
Main
и вызовите созданный методReplaceSpaces
. Но сначала создадим несколько автоматических тестов: будем использовать методAssert
. - В автоматическом тесте вызовем метод с исходной строкой, включающей несколько пробелов подряд:
- Запустите приложение. В консоли должно появиться только сообщение «Тесты пройдены», что означает, что функция работает корректно.
- И наконец, мы должны заменить все подряд идущие пробелы в конкретной строке (из Примерного вывода задания). Объявим строковую переменную и присвоим ей значение:
- Запустите приложение и проверьте его работоспособность.
- Добавьте комментарий с заданием и загрузите файл на проверку.
//... using System.Text.RegularExpressions; //... |
//... using System.Text.RegularExpressions; using System.Diagnostics; //... |
static string ReplaceSpaces(string input, string pattern, string replacement) { ... } |
"\s+"
string pattern = @"\s+"; |
string replacement = " "; |
Replace(string input, string replacement)
: в указанной строке (input string) заменяет все вхождения шаблона на указанную строку замены (string replacement).Regex rgx = new Regex(pattern); string result = rgx.Replace(input, replacement); return result; |
Debug.Assert(ReplaceSpaces(" Good day !",pattern, replacement) == " Good day !"); Console.WriteLine("Тесты пройдены"); |
string input = "Hello World "; Console.WriteLine($"Original String: {input}"); Console.WriteLine($"Replacement String: {ReplaceSpaces(input, pattern, replacement)}"); Console.ReadKey(); |