Руководство Регулярное выражение CSharp

1- Регулярное выражение (Regular expression)

1.1- Обзор

Регулярное выражение (Regular expressions) определяет шаблон (pattern) поиска строк. Оно может быть использовано для поиска, редактирования, и манипулирования текста. Шаблон определяется регулярным выражением, которое может подходить (match) один или несколько раз, или не подходить готовому тексту.

Аббревиатура регулярного выражения является  regex

1.2- Поддерживаемые языки

Регулярное выражение (Regular expression) поддерживается почти всеми языками программирования, например, C#, Java, Perl, Groovy, и т.д... К сожалению каждый язык поддерживает регулярные выражения немного по-разному.

2- Правила написания регулярных выражений

No Регулярное
выражение 
Описание
1 . Подходит (match) одному или многим символам.
2 ^regex Регулярное выражение должно подходить в начале
3 regex$ Регулярное выражение должно подходить в конце строки.
4 [abc] Настроить определение, которое может подходить a или b или c.
5 [abc][vz] Настроить определение, которое может подходить a или b или c последовательно v или z.
6 [^abc] Когда появляется знак ^ как первый персонаж в квадратных скобках, он отрицает модель. Это может подходить любому символу, за исключением a или b или c.
7 [a-d1-7] Рамки: подходит строке между a и пунктом d и числу от 1 до 7.
8 X|Z Найти X или Z.
9 XZ Найти X а потом Z.
10 $ Проверить завершение строки.

11 \d Любое число, написать кратко для [0-9]
12 \D Символ не является числом, написать кратко для​​​​​​​[^0-9]
13 \s Символ пробела, написать кратко для​​​​​​​ [ \t\n\x0b\r\f]
14 \S Символ не является пробелом, написать кратко для​​​​​​​ [^\s]
15 \w Символ буквы, написать кратко для [a-zA-Z_0-9]
16 \W Символ не является буквой, написать кратко для​​​​​​​ [^\w]
17 \S+ Некоторые символы не являющиеся пробелом (Один или много)
18 \b Символ принадлежит a-z или A-Z или 0-9 или _, написать кратко для [a-zA-Z0-9_].

19 * Появляется 0 или много раз, написать кратко для​​​​​​​ {0,}
20 + Появляется 1 или много раз, написать кратко для {1,}
21 ? Появляется 0 или 1 раз, ? написать кратко для​​​​​​​ {0,1}.
22 {X} Появляется X раз, {}
23 {X,Y} Появляется примерно X до Y раз.
24 *? * значит появляется 0 или много раз, добавить ? в конце значит найти наименьшее соответствие

3- Особые символы в  C# Regex (Special characters)

Некоторые особернные символы в  C# Regex:
\.[{(*+?^$|
 
Символы перечисленные выше являются особенными символами. В C# Regex, вы хотите чтобы он понял, что эти символы следуют обычному способу, вам нужно добавить знак \ спереди.

Например символ точки . C# Regex понимает как один или много любых символов, если вы хотите, чтобы он понял как обычную точку, нужно поставить знак \ спереди.
// Шаблон regex описывает один или много символов.
string regex = ".";

// Шаблон regex описывает символ точки.
string regex = "\\.";
string regex = @"\.";

4- Использование Regex.IsMatch(string)

  • Regex class
...
// Проверить, совпадает ли полностью String с regex или нет.
public bool IsMatch(string regex)
..
Используя метод  Regex.IsMatch(string regex) разрешает вам проверить полностью String подходить  regex или нет. Это самый распространенный способ. Смотрите примеры:

Regex .

В регулярном выражении  C#, символ точки (.) является особенным символом. Он представляет один или много символов. Если вы хотите, чтобы  C# понял точку как обычный символ, вам нужно написать "\\." или @"\.";
DotExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class DotExample
    {
        public static void Main(string[] args)
        {
            // Строка с 0 символами (Пустая)          
            string s1 = "";
            Console.WriteLine("s1=" + s1);

            // Проверить строку s1
            // Совпадает с 1 или многими символами.
            // Правило .
            // ==> False
            bool match = Regex.IsMatch(s1, ".");
            Console.WriteLine("  -Match . " + match);

            // Строка с 1 символом.  
            string s2 = "a";
            Console.WriteLine("s2=" + s2);

            // Проверить строку s2
            // Совпадает с 1 или многими символами.
            // Правило .
            // ==> True
            match = Regex.IsMatch(s2, ".");
            Console.WriteLine("  -Match . " + match);

            // Строка с 3 символами.
            string s3 = "abc";
            Console.WriteLine("s3=" + s3);

            // Проверить строку s3
            // Совпадает с 1 или многими символами.
            // Правило .
            // ==> true
            match = Regex.IsMatch(s3, ".");
            Console.WriteLine("  -Match . " + match);

            // Строка с 3 символами.
            string s4 = "abc";
            Console.WriteLine("s4=" + s4);

            // Проверить строку s4
            // Совпадает с символом точки.
            // ==> False
            match = Regex.IsMatch(s4, @"\.");
            Console.WriteLine("  -Match \\. " + match);

            // Строка с 1 символом (Точка).
            string s5 = ".";
            Console.WriteLine("s5=" + s5);

            // Проверить строку s5
            // Совпадает с символом точки.
            // ==> True
            match = Regex.IsMatch(s5, @"\.");
            Console.WriteLine("  -Match \\. " + match);

            Console.Read();
        }
    }

}
Запуск примера:
Другой пример используя  Regex.IsMath(string):
RegexIsMatchExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class RegexIsMatchExample
    {
        public static void Main(string[] args)
        {
            // Строка с 1 символом
            string s2 = "m";
            Console.WriteLine("s2=" + s2);

            // Проверить s2
            // Начинается с символа 'm'
            // Правило ^
            // ==> true
            bool match = Regex.IsMatch(s2, "^m");
            Console.WriteLine("  -Match ^m " + match);

            // Строка с 7 символами
            string s3 = "MMnnnnn";
            Console.WriteLine("s3=" + s3);

            // Првоерить s3
            // Начинается с MM
            // Правило ^
            // ==> true
            match = Regex.IsMatch(s3, "^MM");
            Console.WriteLine("  -Match ^MM " + match);

            // Првоерить s3
            // Начинается с MM
            // Далее появляется символ 'n' один или много раз
            // Quy tắc ^ và +
            match = Regex.IsMatch(s3, "^MMn+");
            Console.WriteLine("  -Match ^MMn+ " + match);

            // Строка с 1 символом
            String s4 = "p";
            Console.WriteLine("s4=" + s4);

            // Проверить s4 заканчивается на 'p'
            // Правило $
            // ==> true
            match = Regex.IsMatch(s4, "p$");
            Console.WriteLine("  -Match p$ " + match);

            // Строка с 6 символами
            string s5 = "122nnp";
            Console.WriteLine("s5=" + s5);


            // Проверить s5 заканчивается на 'p'
            // ==> true
            match = Regex.IsMatch(s5, "p$");
            Console.WriteLine("  -Match p$ " + match);

            // Проверить s5
            // Начинается одним или многими символами (Правило .)
            // Далее следует  'n', появляет от 1 до  3 раз (Правило n{1,3} )
            // Заканчивается символом 'p' (Правило $)
            // Сочетать правила ., {x,y}, $
            // ==> true
            match = Regex.IsMatch(s5, ".n{1,3}p$");
            Console.WriteLine("  -Match .n{1,3}p$ " + match);


            String s6 = "2ybcd";
            Console.WriteLine("s6=" + s6);

            // Проверить s6
            // Начинается с '2'
            // Далее 'x' или 'y' или 'z'  (Правило [xyz])
            // Далее любой появляется 0 или много раз (Правило *)
            match = Regex.IsMatch(s6, "2[xyz].*");

            Console.WriteLine("  -Match 2[xyz].* " + match);

            string s7 = "2bkbv";
            Console.WriteLine("s7=" + s7);

            // Проверить s7, начинается где угодно (один или много раз)
            // Далее 'a' или 'b' или 'c' (Правило [abc] )
            // Далее 'z' или 'v' (Правило [zv] )
            // В конце любой, 0 или много раз (Правило .*)
            // ==> true
            match = Regex.IsMatch(s7, ".[abc][zv].*");

            Console.WriteLine("  -Match .[abc][zv].* " + match);


            Console.Read();
        }
    }


}
Результат запуска примера:
Следующий пример:
RegexIsMatchExample2.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class RegexIsMatchExample2
    {
        public static void Main(string[] args)
        {
            String s = "The film Tom and Jerry!";

            // Проверить строку s
            // Начинается с любого символа, появляется 0 или много раз (Правило: .*)
            // Далее "Tom" или "Jerry"
            // Заканчивается любым символом, появляется 1 или много раз (Правило .)
            // Сочетает правила: ., *, X|Z
            bool match = Regex.IsMatch(s, ".*(Tom|Jerry).");
            Console.WriteLine("s=" + s);
            Console.WriteLine("-Match .*(Tom|Jerry). " + match);

            s = "The cat";
            // ==> false
            match = Regex.IsMatch(s, ".*(Tom|Jerry).");
            Console.WriteLine("s=" + s);
            Console.WriteLine("-Match .*(Tom|Jerry). " + match);

            s = "The Tom cat";
            // ==> true
            match = Regex.IsMatch(s, ".*(Tom|Jerry).");
            Console.WriteLine("s=" + s);
            Console.WriteLine("-Match .*(Tom|Jerry). " + match);

            Console.Read();
        }
    }

}
Результат запуска примера:

5- Using Regex.Split & Regex.Replace

Один из других полезных методов является Regex.Split(string,string), данный метод делит строку на подстроки. Например у вас есть строка  "One,Two,Three" и вы хотите разделить на 3 подстроки, разделенные запятой.
SplitWithRegexExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class SplitWithRegexExample
    {
        public static void Main(string[] args)
        {
            // \t: Символ TAB
            // \n: Символ новой строки (NewLine character).
            string TEXT = "This \t\t is \n my \t text";

            Console.WriteLine("TEXT=" + TEXT);

            // Определить Regex:
            // Пробел появляется 1 или много раз.
            // Символы пробела: \t\n\x0b\r\f
            // Сочетать правила: \s и +
            String regex = @"\s+";

            Console.WriteLine(" -------------- ");

            String[] splitString = Regex.Split(TEXT, regex);

             
            Console.WriteLine(splitString.Length); // ==> 4

            foreach (string str in splitString)
            {
                Console.WriteLine(str);
            }

            Console.WriteLine(" -------------- ");

            // Заменить все пробелы символом tab.
            String newText = Regex.Replace(TEXT, "\\s+", "\t");
            Console.WriteLine("New text=" + newText);

            Console.Read();
        }
    }

}
Запуск примера:

6- Использование MatchCollection & Match

Используйте метод  Regex.Matches(...) для поиска всех подстрок одной строки, подходящей регулярному выражению, данный метод возвращает объект  MatchCollection.
** Regex.Matches() **
public MatchCollection Matches(
    string input
)

public MatchCollection Matches(
    string input,
    int startat
)

public static MatchCollection Matches(
    string input,
    string pattern
)

public static MatchCollection Matches(
    string input,
    string pattern,
    RegexOptions options,
    TimeSpan matchTimeout
)

public static MatchCollection Matches(
    string input,
    string pattern,
    RegexOptions options
)
В примере ниже, строка делится на подстроки, разделенные пробелами (whitespace).
MatchCollectionExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class MatchCollectionExample
    {
        public static void Main(string[] args)
        {

            string TEXT = "This \t is a \t\t\t String";

            // \w : Символ слова, вкратце для [a-zA-Z_0-9]
            // \w+ : Символ слова, появляется один или много раз.
            string regex = @"\w+";


            MatchCollection matchColl = Regex.Matches(TEXT, regex);

            foreach (Match match in matchColl)
            {
                Console.WriteLine(" ---------------- ");
                Console.WriteLine("Value: " + match.Value);
                Console.WriteLine("Index: " + match.Index);
                Console.WriteLine("Length: " + match.Length);
            }


            Console.Read();
        }
    }

}
Результат запуска примера:

7- Группа (Group)

Регулярное выражение вы можете разделить на группы (group):
// Регулярное выражение
string regex = @"\s+=\d+";

// Написать в виде 3 групп (group), со знаком ( )
string regex2 = @"(\s+)(=)(\d+)";

// Две группы (group)
string regex3 = @"(\s+)(=\d+)";
Группы могут быть сплетены, таким образом нужно правило для индексирования групп. Весь шаблон ( pattern) определяется группой 0. Остальные описываются как в изображении ниже:

Примечание: Используйте (?:pattern) чтобы объявить C# не считать это как группу (None-capturing group)

Вы можете определить группу с названием  (?<groupName>pattern) или  (?'groupName'pattern), и вы можете получить доступ ко всему содержанию подходящему  match.Groups["groupName"]. Это делает Regex длинее, но данный код имеет больше значения, легче.

Доступ в именованную группу так же можно получить через match.Groups[groupIndex] с похожим правилом индексирования.
-
Посмотрим пример использования именованной группы (group):
NamedGroupExample.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class NamedGroupExample
    {
        public static void Main(string[] args)
        {
            string TEXT = " int a = 100;  float b= 130;  float c= 110 ; ";

            // Используйте (?<groupName>pattern) для определения группы с названием: groupName
            // Опредалить группу с называнием 'declare': используя (?<declare> ...)
            // И группу с названием 'value': используя: (?<value> ..)
            string regex = @"(?<declare>\s*(int|float)\s+[a-z]\s*)=(?<value>\s*\d+\s*);";

            MatchCollection matchCollection = Regex.Matches(TEXT, regex);


            foreach (Match match in matchCollection)
            {
                string group = match.Groups["declare"].Value;
                Console.WriteLine("Full Text: " + match.Value);
                Console.WriteLine("<declare>: " + match.Groups["declare"].Value);
                Console.WriteLine("<value>: " + match.Groups["value"].Value);
                Console.WriteLine("------------------------------");
            }

            Console.Read();
        }
    }

}
Результат запуска примера:
Чтобы лучше понять, вы можете просмотреть изображение ниже:

8- Использовать MatchCollection, Group и *?

В некоторых случаях  *? очень важен, посмотрим следующий пример:
// Это regex
// Любой символ, появляется 0 или много раз,
// далее идет символ  '  и последовательно >
string regex = ".*'>";

// Строка TEXT1 далее походит с regex выше.
string TEXT1 = "FILE1'>";

// Строка TEXT2 далее походит с regex выше.
string TEXT2 = "FILE1'> <a href='http://HOST/file/FILE2'>";
*? найдет наименьшее соответствие (smallest match). Посмотрим следующий пример:
NamedGroupExample2.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;

namespace RegularExpressionTutorial
{
    class NamedGroupExample2
    {
        public static void Main(string[] args)
        {

            string TEXT = "<a href='http://HOST/file/FILE1'>File 1</a>"
                         + "<a href='http://HOST/file/FILE2'>File 2</a>";

            // Определить группу с названием fileName.
            // * значит появиться 0 или много раз.
            // *? значит наименьшее соответствие (smallest match).
            string regex = "/file/(?<fileName>.*?)'>";

            MatchCollection matchCollection = Regex.Matches(TEXT, regex);


            foreach (Match match in matchCollection)
            {
                Console.WriteLine("File Name = " + match.Groups["fileName"].Value);
                Console.WriteLine("------------------------------");
            }

            Console.Read();
        }
    }

}
Результат запуска примера: