Регулярные выражения в С#. Класс Regex 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Регулярные выражения в С#. Класс Regex



 

Регулярное выражение – это некий шаблон, составленный из символов и спецсимволов, который позволяет находить подстроки соответствующие этому шаблону в других строках. Спецсимволов и различных правил их комбинирования очень много, поэтому регулярные выражения можно даже отнести к отдельному языку программирования. Например, при поиске по файлам в Windows для того чтобы найти файлы заданного расширения txt, задается шаблон типа «*.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();

}

 

Пользовательские функции

 

Функции в С# — это средство, позволяющее выполнять некоторые участки кода в произвольном месте приложения. Они позволяют делать программу более удобочитаемой, и группировать вместе логически связанные между собой части программ. Функцию можно представить себе как повторно используемый код.

Параметры и возвращаемое значение функции вместе называются заголовком, или сигнатурой функции.

Синтаксис кода для простейшей функций консольного приложения будет выглядеть следующим образом:

 

static void <имяФункции>()

{

...

}

 

Ключевое слово static имеет отношение к понятиям объектно-ориентированного программирования, и гарантирует выполнение функции. Ключевое слово void (отсутствует) указывает, что функция не возвращает никакого значения.

Если функция должна возвращать вовне какие-либо данные, то синтаксис следующий:

 

static <возвращаемыйТип> <имяФункции>()

{

...

return <возвращаемоеЗначение>

 

}

 

Единственным ограничением в данном случае является требование того, ЧТО <возвращаемоеЗначение> ДОЛЖНО иметь ТИП <возвращаемыйТип> ИЛИ же должна существовать возможность его неявного преобразования в этот тип.

 

В простейшем случае это может выглядеть следующим образом:

 

static double getVal()

{

return 3.2;

}

 

Если же функция должна принимать извне какие-либо данные, то необходимо задать:

­ список принимаемых функцией параметров в ее описании, а также типы этих параметров;

­ совпадающий список параметров при каждом вызове функции.

 

Это предполагает использование следующего кода:

 

static <возвращаемыйТип> <имяФункции>(<типПараметра> <имяПараметра>, …)

{

...

return <возвращаемоеЗначение>

}

 

Здесь может быть произвольное число параметров, для каждого из которых указываются тип и уникальный идентификатор. В качестве разделителя между параметрами ставятся запятые. Каждый из параметров доступен внутри данной функции в качестве переменной. Например, следующая простая функция принимает два параметра типа double и возвращает их произведение:

 

static double product(double param1, double param2)

{

return paraml * param2;

}

 

Следует отметить, что когда при выполнении программы достигается оператор return, управление немедленно передается обратно в вызывающий код. Никакие строки кода после этого оператора выполняться не будут. Оператор return не обязательно должен быть последним. Он может быть использован и раньше, например, при ветвлении по какому-либо условию. Включение оператора return в цикл for, в блок if или в какую-нибудь другую структуру приведет к немедленному окончанию выполнения как этой структуры, так и всей функции в целом.

 

static string Inverse(double val)

{

if (val == 0) return "Аргумент равен нулю!";

return Convert.ToString(1 / val);

}

Здесь при выполнении условия (val == 0) в точку вызова будет возвращено сообщение, а вторая строка тела функции не выполнится. Иначе будет возвращен строковый эквивалент обратного значения аргумента.

 

Более сложный пример для решения задачи по обработке строк.

Задана строка, состоящая из слов, разделенных пробелами. Вывести на экран из исходной строки слова, которые, начинаются и заканчиваются одной и той же буквой, причем эта буква в слове больше не повторяется. В основную программу вернуть количество выведенных слов.

 

Решение.

Так как результатом решения задачи является вывод слов на экран, функция может иметь следующую сигнатуру: static int PrintWords(string TargetString)

 

Код функции PrintWords:

 

string s = TargetString.Trim().ToLower() + " ";

// Удаление пробелов в начале и в конце строки, перевод в нижний регистр и

// добавление 1 пробела в конце, чтобы можно было определить конец последного слова.

// Скорректированная строка в переменной s

int i, j, k, n, kol;

char b = ' '; // Переменная для хранения первой буквы слова

k = 0; // счетчик вхождений первой буквы внутри слова

n = 0; // позиция символа в текущем слове

j = 0; // координата начала текущего слова

kol = 0; // счетчик выведенных слов

for (i = 0; i < s.Length; i++)

{

if (s[i] == ' ') continue; // Если пробел, то переход к следующей итерации

n++; // следующий символ в слове

if (n == 1) // Если это первый символ в слове,

{

   b = s[i]; // то запоминаем его в b

   j = i; // и запоминаем начало слова в j

}

else

{

   if (s[i + 1] == ' ') // Если это последний символ в слове ТО

   {

       if ((s[i] == b) && (k == 0)) // Если последний символ равен первому

       {                      // И внутри слова повторнеий не было ТО

           if (kol == 0) // Если это превое найденное слово

               Console.WriteLine("\nОбнаруженные слова:"); // то выводим сообщение

           kol++; // наращиваем счетчик выведенных слов

           Console.WriteLine(s.Substring(j, n)); // выделяем слово и выводим на экран

       }

       k = n = 0; // переходим к следующему слову

   }

     else if (s[i] == b) // Если внутри слова обнаружена первая буква,

            k++;  // то увеличиваем счетчик на 1

}

}

return kol;

 

// Конец тела функции PrintWords

 

Код метода Main(), который содержит все, что требуется по заданию, за исключением вывода результата решения задачи (он выведен в функции):

 

Console.WriteLine("Введите заданную строку со словами через пробелы: ");

string s = Console.ReadLine();

if (0 == PrintWords(s)) Console.WriteLine("\nСлов с заданными параметрами не найдено.");

Console.ReadKey();

 

Результат выполнения метода Main():

Введите заданную строку со словами через пробелы:

Однако в поездах Интерсити отопление вагонов отсутствовало

 

Обнаруженные слова:

однако

вагонов

Задание

 

1. Проанализировать индивидуальное задание из таблицы 9 и определить сигнатуру функции для решения заданной задачи (идентификатор функции, идентификаторы и типы данных аргументов, тип возвращаемых данных).

2. Разработать код тела функции на языке C#, которая реализует заданную задачу по обработке строк и возвращает требуемые результаты. Решить задачу с использованием и без использования регулярных выражений.

3. Разработать код метода Main(), который содержит:

­ вывод инструкций для ввода исходных данных для заданной задачи;

­ ввод исходных данных с клавиатуры;

­ вызов разработанной функции, выполняющей решение задачи;

­ вывод результата решения задачи.

4. Разработать блок-схемы алгоритмов для разработанной функции и для метода Main().

5. Выполнить ручной просчет.

6. Сделать вывод по работе.

 

Таблица 9. Варианты индивидуальных заданий по обработке строк

№ варианта Задание
1 Заданная строка состоит из строчных букв и включает несколько предложений, заканчивающихся точкой. Первые буквы предложений, начиная с n-го, сделать прописными. В основную программу вернуть количество преобразованных предложений. Если в строке нет n-го предложения (возвращенное значение – 0), то вывести соответствующее сообщение.
2 Выделить из строки заданное количество слов, начиная со слова с номером n. В основную программу вернуть количество выделенных слов. Если в строке нет n-го слова (возвращенное значение – 0), то вывести соответствующее сообщение.
3 Исходная строка содержит список русских фамилий мужского рода (не более 10) через запятую. Преобразовать список таким образом, чтобы вначале шли все фамилии с окончанием -ев, затем фамилии с окончанием -ин, затем фамилии с окончанием -ов, и далее все остальные фамилии. Относительная последовательность фамилий в каждой группе должна быть та же, что и в исходном списке. В основную программу вернуть четырехзначное натуральное число, каждый разряд которого равен количеству фамилий в соответствующей группе.
4 "Перевернуть" в строке все слова. (Например: "Жили были дед и баба" - "илиЖ илиб дед и абаб"). В основную программу вернуть количество слов в строке.
5 Определить длину n-го слова, и все слова, которые длиннее n-го слова, преобразовать в верхний регистр. Если n-е слово самое длинное, то вывести сообщение. В основную программу вернуть длину n-го слова. Если в строке нет n-го слова (возвращенное значение – 0), то вывести соответствующее сообщение.
6 Ввести текст, содержащий только символы латинского алфавита и знаки препинания (:;,.). Подсчитать статистику употребления в тексте следующих символов: “a, b, c, d, e, f, g”. Вывести на экран диаграмму, отображающую статистику по каждой из заданных букв. Например:        A| aaaaaaaaa        B| bb        C|        D|ddddd        … В основную программу вернуть количество обнаруженных в строке знаков препинания.
7 Найти в строке первый символ, который не входит в другую заданную строку. В основную программу вернуть позицию этого символа.
8 В каждом слове строки заданную букву в нечетной позиции удалить, а в четной позиции заменить символом подчеркивания (_). В основную программу вернуть разность количеств сделанных удалений и замен
9 Заменить в строке заданный символ на символ * n раз, начиная с заданной позиции. В основную программу вернуть фактическое количество замен.
10 Удалить из строки n-е слово. В основную программу вернуть длину удаленного слова, либо 0, если n-е слово не найдено.
11 Разбить строку на две части: до и после первого вхождения заданного символа. В основную программу вернуть позицию заданного символа, либо 0, если такой символ не найден.
12 Найти в строке два одинаковых фрагмента (не включающих в себя пробелы) длиной более 5 символов и возвратить индекс начала первого из них (т.е. для " aaaaaabcdefgxxxxxxbcdefgwwwww" вернуть n=6 - индекс начала " bcdefg")
13 Переписать все символы строки в обратном порядке. В результатной строке удалить все слова, начинающиеся с буквы А
14 Переписать строку. Если в строке обнаруживается число, то вместо него переписать в выходную строку соответствующее по счету слово из входной строки (например, " aaa bb1bb cc2cc" - " aaa bbaaabb ccbb1bbcc")
15 Переписать в выходную строку слова из входной строки в порядке возрастания их длины.
16 Заменить в строке все множественные вхождения заданного символа одним
17 Нечетные слова в строке заменить наборами звездочек соответствующей длины
18 Заменить в строке все целые числа соответствующим повторением следующего за ними символа (например "abc5xacb15y" - " abcxxxxxacbyyyyyyyyyyyyyyy ")
19 Удалить из строки все буквы А независимо от регистра, а также знаки препинания
20 Выделить из заданной строки подстроку заданной длины, начиная с заданной буквы (символа). Если такого символа нет, то выводить сообщение.
21 Оставить в строке фрагменты, симметричные центрального символа, длиной более 5 символов (например, " dcbabcd"), остальные символы заменить на пробелы.
22 Довести длину строки до заданной, вставляя пробелы между словами.

 

Лабораторная работа №6

 

Тема: Работа с текстовыми файлами

 

Цель: изучить и освоить использование текстовых файлов для длительного хранения данных; закрепить навыки составления и тестирование алгоритмов и программ, использующих потоки файлового ввода-вывода.

 

Теоретические положения

 



Поделиться:


Последнее изменение этой страницы: 2021-09-26; просмотров: 208; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.139.233.43 (0.171 с.)