Regex c что это
Перейти к содержимому

Regex c что это

  • автор:

Введение в регулярные выражения в современном C++

Привет, Хабр. Будущих студентов курса «C++ Developer. Professional» приглашаем записаться на открытый урок по теме «Backend на современном C++»


А пока делимся традиционным переводом полезного материала.

Регулярные выражения (Regular expressions или, вкратце, regex — регулярки) — это пока что непопулярная и недооцененная тема в современном C++. Но в то же время разумное использование регулярных выражений может избавить вас от написания множества строчек кода. Если у вас уже есть какой-никакой опыт работы в индустрии, но вы не умеете использовать регулярные выражения — вы разбазариваете 20-30% своей продуктивности. Я настоятельно рекомендую вам освоить регулярные выражение, так как это единовременная инвестиция в себя (по известному принципу “learn once, write anywhere”).

/!\: Изначально эта статья была опубликована в моем личном блоге. Если вам станет интересно и дальше читать мои самые актуальные статьи, вы можете подписаться на мою рассылку.

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

Примечание: стандартная библиотека C++ предлагает несколько различных разновидностей («flavours») синтаксиса регулярных выражений, но вариант по умолчанию (тот, который вы всегда должны использовать, и который я демонстрирую здесь) был полностью позаимствован из стандарта ECMAScript.

Мотивация

Я понимаю, инструментарий регулярок скуден и достаточно запутан. Рассмотрим приведенный ниже шаблон регулярного выражения, который извлекает время в 24-часовом формате (т.е. ЧЧ:ММ), в качестве примера.

\b([01]?[0-9]|2[0-3]):([0-5]\d)\b

Вот да! Кто захочет возиться с этим непонятным текстом?

И все, что приходит вам в голову, глядя на это, на 100% небезосновательно. Я сам дважды откладывал изучение регулярных выражений по той же причине. Но, поверьте, этот неприглядный инструмент не так уж и плох.

Подход (↓), который я здесь описываю, не отнимет у вас больше 2-3 часов на изучение регулярных выражений, которые, по правде говоря, интуитивно понятны. После того, как вы их освоите, вы увидите, что с течением времени ваша инвестиция дает стабильные дивиденды.

Изучение регулярных выражений

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

После этого, если у вас осталось желание порешать побольше задач и упражнений, рассмотрите приведенные ниже ссылки:

  1. Упражнения на regextutorials.com
  2. Практические задачи с регулярными выражениями на hackerrank

Пример std::regex и std::regexerror

int main() < try < static const auto r = std::regex(R"(\)"); // Escape sequence error >catch (const std::regex_error &e) < assert(strcmp(e.what(), "Unexpected end of regex when escaping.") == 0); assert(e.code() == std::regex_constants::error_escape); >return EXIT_SUCCESS; >

Вот видите! Я использую сырые строковые литералы. Вы также можете использовать обычную строку, но в таком случае вы должны использовать двойной бэкслеш (\) для escape-последовательности.

Текущая реализация std::regex медленная (так как требует интерпретации регулярных выражений и создания структуры данных во время выполнения), раздувается и неизбежно требует динамического выделения памяти (не allocator aware). Будьте осторожны, если вы используете std::regex в цикле (см. C++ Weekly — Ep 74 — std::regex optimize by Jason Turner). Кроме того, в ней есть только одна функция-член, которая, как я думаю, действительно может быть полезной — это std::regex::markcount() , которая возвращает несколько групп захвата.

Более того, если вы используете несколько строк для создания шаблона регулярного выражения во время выполнения, то вам может потребоваться обработка исключений (например, std::regexerror) , чтобы проверить его правильность.

Пример std::regex_search

int main() < const string input s; const regex r(R"((\w+):(\w+);)"); smatch m; if (regex_search(input, m, r)) < assert(m.size() == 3); assert(m[0].str() == "PQR:2;"); // Entire match assert(m[1].str() == "PQR"); // Substring that matches 1st group assert(m[2].str() == "2"); // Substring that matches 2nd group assert(m.prefix().str() = ); // All before 1st character match assert(m.suffix().str() == ";; XYZ:3<<<"); // All after last character match // for (string &&str : m) < // Alternatively. You can also do // cout << str << endl; // >> return EXIT_SUCCESS; >

smatch — это специализация std::match_results, которая хранит информацию о найденных совпадениях (матчах).

Пример std::regex_match

Лаконичный и приятный пример, который вы всегда можете найти в каждой книге о регулярках, — это валидация электронной почты. И именно здесь идеально подходит функция std::regexmatch .

bool is_valid_email_id(string_view str) < static const regex r(R"(\w+@\w+\.(?:com|in))"); return regex_match(str.data(), r); >int main()

return EXIT¨C14Cmatch , а не std::regex¨C15Cmatch сопоставляет (матчит) всю входную последовательность.

Еще одна примечательная вещь — это статический объект регулярного выражения (static const regex), чтобы избежать создания («компиляции/интерпретации») нового объекта регулярного выражения каждый раз при заходе в функцию.

Вся ирония этого крошечного фрагмента кода заключается в том, что он генерирует порядка 30 тысяч строк сборки с флагом -O3. И это просто смешно. Но не волнуйтесь, это уже было доведено до комитета ISO C++. И в скором времени мы можем получить обновление, устраняющее проблему. Между тем у нас есть и другие альтернативы (упомянутые в конце этой статьи).

Разница между std::regex_match и std::regex_search

Вам может быть интересно, почему у нас есть две функции, выполняющие почти одинаковую работу? Даже я изначально не понимал этого. Но после многократного прочтения описания, предоставляемого cppreference, я нашел ответ. И чтобы объяснить этот ответ, я создал пример (очевидно, не без помощи StackOverflow):

int main()

std::regexmatch возвращает true только тогда, когда совпадает ​​вся входная последовательность, в то время как std::regexsearch вернет true , даже если только часть последовательности соответствует регулярному выражению.

Пример std::regex_iterator

std::regex_iterator полезен, когда требуется очень подробная информация о соответствиях и сабматчах.

#define C_ALL(X) cbegin(X), cend(X) int main() < const string input s; const regex r(R"((\w+):(\d))"); const vectormatches< sregex_iterator, sregex_iterator<> >; assert(matches[0].str(0) == "ABC:1" && matches[0].str(1) == "ABC" && matches[0].str(2) == "1"); assert(matches[1].str(0) == "PQR:2" && matches[1].str(1) == "PQR" && matches[1].str(2) == "2"); assert(matches[2].str(0) == "XYZ:3" && matches[2].str(1) == "XYZ" && matches[2].str(2) == "3"); return EXIT_SUCCESS; >

Ранее (в C++11) существовало ограничение, заключающееся в том, что std::regex_interator нельзя было вызывать с временным объектом регулярного выражения. Что было исправлено с помощью перегрузки в C++14.

Пример std::regex_token_iterator

std::regextokeniterator — это утилита, которую вы будете использовать в 80% случаев. Она немного отличается от std::regexiterator . Разница между td::regexiterator и std::regextokeniterator заключается в том, что

  • std::regexiterator указывает на соответствующие результаты.
  • std::regextokeniterator указывает на сабматчи.

В std::regextoken_iterator каждый итератор содержит только один соответствующий результат.

#define C_ALL(X) cbegin(X), cend(X) int main() < const string input s; const regex r(R"((\w+):(\d))"); // Note: vectorhere, unlike vector as in std::regex_iterator const vector full_match< sregex_token_iterator, // Mark `0` here i.e. whole regex match sregex_token_iterator<> >; assert((full_match == decltype(full_match))); const vector cptr_grp_1st< sregex_token_iterator, // Mark `1` here i.e. 1st capture group sregex_token_iterator<> >; assert((cptr_grp_1st == decltype(cptr_grp_1st))); const vector cptr_grp_2nd< sregex_token_iterator, // Mark `2` here i.e. 2nd capture group sregex_token_iterator<> >; assert((cptr_grp_2nd == decltype(cptr_grp_2nd))); return EXIT_SUCCESS; >

Инверсия соответствия с std::regex_token_iterator

#define C_ALL(X) cbegin(X), cend(X) int main() < const string input s; const regex r(R"((\w+):(\d))"); const vectorinverted< sregex_token_iterator, // `-1` = parts that are not matched sregex_token_iterator<> >; assert((inverted == decltype(inverted) < "", "->", ";;; ", ")); return EXIT_SUCCESS; >

Пример std::regex_replace

string transform_pair(string_view text, regex_constants::match_flag_type f = <>) < static const auto r = regex(R"((\w+):(\d))"); return regex_replace(text.data(), r, "$2", f); >int main() < assert(transform_pair("ABC:1, PQR:2"s) == "1, 2"s); // Things that aren't matched are not copied assert(transform_pair("ABC:1, PQR:2"s, regex_constants::format_no_copy) == "12"s); return EXIT_SUCCESS; >

Вы видите, что во втором вызове transformpair мы передали флаг std::regexconstants::formatnocopy , который говорит не копировать те части, которые не соответствуют регулярке. В std::regexconstant есть много подобных полезных флагов.

Кроме того, мы создали новую строку, содержащую результаты. Но что, если нам не нужна новая строка, а нужно добавить результаты куда-нибудь, возможно, в контейнер, поток или уже существующую строку. Угадайте, что! Стандартная библиотека уже реализует такую потребность также с помощью перегруженного std::regexreplace следующим образом:

int main() < const string input s; const regex r(R"(-|>|<|;| )"); // Prints "ABC:1 PQR:2 XYZ:3 " regex_replace(ostreambuf_iterator(cout), C_ALL(input), r, " "); return EXIT_SUCCESS; >

Примеры использования

Разделение строки с помощью разделителя (delimiter)

std::strtok является наиболее подходящим и оптимальным кандидатом для такой задачи, но в целях демонстрации продемонстрируем как это можно сделать с помощью регулярного выражения:

#define C_ALL(X) cbegin(X), cend(X) vector split(const string& str, string_view pattern) < const auto r = regex(pattern.data()); return vector< sregex_token_iterator(C_ALL(str), r, -1), sregex_token_iterator() >; > int main() < assert((split("/root/home/vishal", "/") == vector)); return EXIT_SUCCESS; >

Удаление пробелов из строки

string trim(string_view text) < static const auto r = regex(R"(\s+)"); return regex_replace(text.data(), r, ""); >int main()

Поиск строк, содержащих или НЕ содержащих определенные слова, из файла

string join(const vector& words, const string& delimiter) < return accumulate(next(begin(words)), end(words), words[0], [&delimiter](string& p, const string& word) < return p + delimiter + word; >); > vector lines_containing(const string& file, const vector& words) < auto prefix = "^.*?\\b("s; auto suffix = ")\\b.*$"s; // ^.*?\b(one|two|three)\b.*$ const auto pattern = move(prefix) + join(words, "|") + move(suffix); ifstream infile(file); vectorresult; for (string line; getline(infile, line);) < if(regex_match(line, regex(pattern))) < result.emplace_back(move(line)); >> return result; > int main() < assert((lines_containing("test.txt", ) == vector)); return EXIT_SUCCESS; > /* test.txt This is one This is two This is three This is four */

То же самое касается поиска строк, которые не содержат слов с шаблоном ^((?!(one|two|three)).)*$ .

Поиск файлов в папке

namespace fs = std::filesystem; vector find_files(const fs::path &path, string_view rg) < vectorresult; regex r(rg.data()); copy_if( fs::recursive_directory_iterator(path), fs::recursive_directory_iterator(), back_inserter(result), [&r](const fs::directory_entry &entry) < return fs::is_regular_file(entry.path()) && regex_match(entry.path().filename().string(), r); >); return result; > int main() < const auto dir = fs::temp_directory_path(); const auto pattern = R"(\w+\.png)"; const auto result = find_files(fs::current_path(), pattern); for (const auto &entry : result) < cout return EXIT_SUCCESS; >

Общие советы по использованию регулярных выражений

  • Для описания шаблона регулярного выражения в C++ лучше используйте сырые строковые литералы.
  • Пользуйтесь инструментом проверки регулярных выражений, например https://regex101.com. Что мне нравится в regex101, так это функция генерации кода и вычисление затраченного времени (будет полезна при оптимизации регулярного выражения).
  • Кроме того, хорошим тоном будет добавление объяснения, сгенерированного инструментом проверки, в виде комментария над шаблоном регулярного выражения в вашем коде. Производительность:
    • Если вы используете чередование (alternation), попробуйте расположить параметры в порядке наивысшей вероятности, например com|net|org .
    • Старайтесь использовать ленивые квантификаторы.
    • По возможности используйте группы без захвата.
    • Отключайте бэктрекинг.
    • Использование отрицательного класса символов более эффективно, чем использование ленивой точки.

    Заключение

    Дело не в том, будете ли вы использовать регулярные выражения исключительно на C++ или любым другим языком. Я сам использую их в основном в IDE (в vscode для анализа файлов логов) и на терминале Linux. Имейте в виду, что чрезмерное использование регулярных выражений дает чрезмерное ощущение собственной сообразительности. И это отличный способ рассердить на вас ваших коллег (и всех, кому нужно работать с вашим кодом). Кроме того, регулярные выражения являются излишними для большинства задач синтаксического анализа, с которыми вы столкнетесь в своей повседневной работе.

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

    Еще одна примечательная вещь — текущая реализация регулярных выражений (до 19 июня 2020 года) в стандартных библиотеках имеет проблемы с производительностью и раздутием кода. Так что выбирайте с умом между версиями библиотек Boost, CTRE и Std. Скорее всего, вы согласитесь с работой Ханы Дусиковой над регулярным выражением времени компиляции. Кроме того, ее выступление на CppCon в 2018 и 2019 было бы для вас полезно, особенно если вы планируете использовать регулярное выражение во встроенных системах.

    printРегулярные выражения

    printRE в C++

    Для работы с RE в С++ используется класс regex, которому в качестве аргумента передается строка, содержащая RE. Так как RE может содержать много символов \, которые в обычной строке C++ необходимо удваивать, для RE можно использовать синтаксическую конструкцию R" `r` ( ) `r` ", где `r` – одна и та же последовательность символов (возможно пустая), без символов скобок, пробелов и \. Символом завершения строки является не ", а целая последовательность, которую можно выбирать самостоятельно. Например, R"@@(\n")")@@" соответствует строке \n")", которая при использовании обычного синтаксиса записывается как «\\n\")\"«.

    Вторым аргументом конструктора можно указать набор флагов, среди которых формат регулярного выражения, флаг icase для игнорирования регистра букв, флаг nosubs для интерпретации подвыражения ( ) как (?: ), флаг оптимизации optimize (если разработчики компилятора предусмотрели такую возможность), флаг collate для учета текущих национальных настроек (локали) при указании диапазона символов (например, множество [а-я] включает букву ё). По умолчанию используется формат ECMAScript (более известном как JavaScript), остальные варианты: basic, extended, awk, grep, egrep – имеют меньше возможностей и предназначены для обеспечения совместимости со стандартами POSIX и некоторыми приложениями. Все флаги объявлены в пространстве имен std::regex_constants.

    В RE для ECMAScript можно делать отсылки к подвыражениям в ( ) вида \№, где № – номер подвыражения. Например, RE (a+)b\1 требует, чтобы строка содержала одинаковое количество букв a до и после b. Эта возможность не может быть реализована с помощью конечного автомата, но полезна для обработки сложных текстов, поэтому в С++ применяется рекурсивный перебор.

    Для работы с RE в C++ используются следующие функции и итераторы.

    Функция regex_match проверяет, соответствует ли вся строка заданному RE, а функция regex_search проверяет, есть ли подстрока, соответствующая заданному RE. Для обоих функций первым аргументом нужно указать строку, далее нужно указать либо RE, либо переменную класса smatch, куда будет помещен результат сопоставления, а затем RE. Методы класса smatch позволяют получить подстроки, соответствующие подвыражениям, их позицию и длину (см. пример). В качестве аргумента этим методам нужно указать номер подвыражения (по умолчанию номер равен 0 – вся подстрока, соответствующая RE).

    string x=»12/7″; string z=»color: #ff0000;»; regex re(R»((\d+)/(\d+))»); regex color_re(«#[a-f0-9]»); if(regex_match(x,re)) coutelse coutif(regex_match(x,parts,re)) < coutпозиция и длина подстроки для 2-го подвыражения cout if(regex_search(z,parts,color_re))

    Функция regex_replace позволяет заменить текст, соответствующая заданному RE. Первым аргументом нужно указать строку с текстом, вторым – RE, третьим – строку с правилом замены. В опциональном четвертом аргументе можно указать флаги format_first_only (заменять только первое соответствие) и format_no_copy (не помещать в результат части текста, не соответвущие RE). В правиле замены используются следующие обозначения: $$ – символ $; $& – подстрока, соответствующая всему RE; $№ (где № от 1 до 99) – подстрока, соответствующая №-му подвыражению RE; $` – часть строки до соответствия; $' – часть строки после соответствия.

    string y="Christmas holiday from 12/21/2015 to 01/03/2016"; regex date_re(R"((\d+)/(\d+)/(\d+))"); // замена формата всех дат в тексте с m/d/y на d-m-y cout
    

    Для более сложной обработки текста используются классы-итераторы sregex_iterator и sregex_token_iterator. Первым и вторым аргументом конструктора обоих классов указывается начало и конец обрабатываемой последовательности, третьим – RE. Для класса sregex_token_iterator четвертым аргументом указывается номер анализируемого подвыражения RE, по умолчанию 0 – соответствие всему RE. Можно указать –1 – для обработки частей строки, не соответствующих RE. Конструкторы без аргументов для обоих классов используется для проверки на завершение обработки (см. пример). Основное отличие между классами – на что указывает итератор. Итератор sregex_iterator указывает на значение класса smatch и можно обрабатывать подстроки, соответствующие подвыражениям RE, а итератор sregex_token_iterator указывает на значение класса ssub_match, в котором определена только операция преобразования к string и метод str() с тем же эффектом (т.е. можно считать это значением типа string).

    // выделение резервированных слов прописными буквами, а идентификаторов - строчными // 1я подстрока выделяет резервированные слова, 2я - идентификаторы regex kw_re(R"((begin|end|for|do|var)|([a-z_]\w*))",regex_constants::icase); int p=0; string s("var I:integer;begin i:=1; End."),r; for(auto t=sregex_iterator(s.begin(),s.end(),kw_re); t!=sregex_iterator();++t) < r+=t->prefix().str(); for(p=t->position();pposition()+t->length();++p) if(t->length(1)) // 1я подстрока не пустая - резервированное слово r+=toupper(s[p]); else // идентификатор r+=tolower(s[p]); > r+=s.substr(p); cout выбрать все слова в тексте txt regex space_re(R"(\s+)"); // пробелы for(auto t=sregex_token_iterator(txt.begin(),txt.end(),space_re,-1); t!=sregex_token_iterator();++t) < cout// выбрать все ссылки в гипертексте htm regex ref_re(R"!()!"); for(auto t=sregex_token_iterator(htm.begin(),htm.end(),ref_re,1); t!=sregex_token_iterator();++t)

    В стандарте C++ почему-то отсутствует вариант regex_replace, где в качестве 3-го аргумента можно было бы указать функцию или лямбда-выражение, которая производит замену по более сложным правилам, чем простая подстановка, хотя эта возможность присутствует в библиотеке boost и других языках программирования. Можно воспользоваться следующим вариантом:

    template typename Function> string regex_replace(const string &s, const regex &re, Function f) < string r; sregex_iterator t(s.begin(),s.end(),re),end; int last=0; for(;t!=end;++t) < r+=t->prefix().str()+f(*t); last=t->position()+t->length(); > return r+=s.substr(last); > // Пример использования - замена на аббревиатуры string s("Artificial Intelligence in Computer Science is an ideal "intelligent" machine."); regex ab(R"(\b[A-Z][a-z]+( [A-Z][a-z]+)+\b)"); cout<const smatch &m)< return m.str()+" ("+regex_replace(m.str(),regex(R"([a-z ]+)"),"")+")"; >)
    

    Для небольших строк можно использовать в цикле regex_search с заменой строки на суффикс строки после найденного RE (задача Abbreviation с NEERC 2016):

    int main() < string s; regex ab(R"(\b[A-Z][a-z]+( [A-Z][a-z]+)+\b)"),na(R"([a-z ]+)"); smatch m; while(getline(cin,s)) < while(regex_search(s,m,ab)) < coutcout >

    Какие есть регулярные выражения в Си?

    Здравствуйте! В переменной есть текст, в котором нужно найти информацию. Я планирую это сделать с помощью регулярных выражений. Столкнулся с проблемой при написании на Си. Заголовочный файл в MS VS 2010 отсутствует, есть файл , но работать с ним нельзя, так как он предназначен для C++, а я пишу на C(Си). Подскажите, есть какая-то альтернативная библиотека/заголовочный файл или способ установки файла в VS? Спасибо! PS Я так уперто пишу на Си, так как хочу перейти потом на objective-c. Или можно спокойно переходить на C++, так как это не повлечёт проблем при написании на objective-c? Или я ошибаюсь? ЗЗЫ Уважаемый @ХэшКод, подскажите, пожалуйста, почему у меня пропала кнопка "добавить комментарий" - я не могу ответить на вопросы?

    Отслеживать

    ВладиславМСК

    задан 22 июл 2012 в 17:39

    ВладиславМСК ВладиславМСК

    1,551 11 11 золотых знаков 38 38 серебряных знаков 59 59 бронзовых знаков

    А просто запихнуть в проект regex.h почему не хотите?

    22 июл 2012 в 17:41

    @knes, а вы уверены, что там нет каких-то ещё сторонних которых тоже не будет в VS 2010?

    22 июл 2012 в 17:47

    > так как это не повлечёт проблем при написании на objective-c Умение мыслить - вот то, что избавит проблем от написания на любом ЯП. Я сразу с Паскаля перешел.

    22 июл 2012 в 17:48

    @VioLet, ну как успехи? Есть свои приложения в AppStore?

    Элементы языка регулярных выражений — краткий справочник

    Регулярное выражение – это шаблон, который обработчик регулярных выражений пытается сопоставить с введенным текстом. Шаблон состоит из односимвольных или многосимвольных литералов, операторов или конструкций. См. краткое описание регулярных выражений .NET.

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

    Мы также представили эту информацию в двух форматах, чтобы вы могли ее скачать и распечатать для справки:

    • Загрузить в формате Word (DOCX)
    • Скачать в формате PDF

    Escape-знаки

    Обратная косая черта (\) в регулярных выражениях указывает, что следующий за ней символ либо является специальным знаком (как показано в следующей таблице), либо должен интерпретироваться буквально. Дополнительные сведения см. в разделе Escape-символы.

    Escape-символ Описание Шаблон Число соответствий
    \a Соответствует знаку колокольчика, \u0007. \a "\u0007" в "Error!" + '\u0007'
    \b В классе символов соответствует знаку BACKSPACE, \u0008. [\b]

    "\b\b\b\b" в "\b\b\b\b"
    \t Соответствует знаку табуляции, \u0009. (\w+)\t "item1\t" , "item2\t" в "item1\titem2\t"
    \r Соответствует знаку возврата каретки, \u000D. ( \r не эквивалентен знаку начала новой строки, \n .) \r\n(\w+) "\r\nThese" в "\r\nThese are\ntwo lines."
    \v Соответствует знаку вертикальной табуляции, \u000B. [\v]

    "\v\v\v" в "\v\v\v"
    \f Соответствует знаку перевода страницы, \u000C. [\f]

    "\f\f\f" в "\f\f\f"
    \n Соответствует знаку новой строки, \u000A. \r\n(\w+) "\r\nThese" в "\r\nThese are\ntwo lines."
    \e Соответствует escape-знаку, \u001B. \e "\x001B" в "\x001B"
    \ Nnn Использует восьмеричное представление для указания символа (nnn состоит из двух или трех цифр). \w\040\w "a b" , "c d" в "a bc d"
    \x Nn Использует шестнадцатеричное представление для указания символа (nn состоит ровно из двух цифр). \w\x20\w "a b" , "c d" в "a bc d"
    \c X

    Классы символов

    Класс символов соответствует какому-либо одному набору символов. Классы символов состоят из языковых элементов, приведенных в следующей таблице. Дополнительные сведения см. в разделе Классы символов.

    Класс знаков Описание Шаблон Число соответствий
    [ character_group ] Соответствует любому одному символу в character_group. По умолчанию при сопоставлении учитывается регистр. [ae] "a" в "gray"

    Привязки

    Привязки, или атомарные утверждения нулевой ширины, приводят к успеху или сбою сопоставления, в зависимости от текущей позиции в строке, но не предписывают обработчику перемещаться по строке или обрабатывать символы. Метасимволы, приведенные в следующей таблице, являются привязками. Дополнительные сведения см. в разделе Привязки.

    Утверждение Описание Шаблон Число соответствий
    ^ По умолчанию соответствие должно начинаться в начале строки. В многострочном режиме соответствие должно начинаться в начале линии. ^\d

    "901" в "901-333-"
    $ По умолчанию соответствие должно обнаруживаться в конце строки или перед символом \n в конце строки. В многострочном режиме соответствие должно обнаруживаться до конца линии или перед символом \n в конце линии. -\d$ "-333" в "-901-333"
    \A Соответствие должно обнаруживаться в начале строки. \A\d

    "901" в "901-333-"
    \Z Соответствие должно обнаруживаться в конце строки или до символа \n в конце строки. -\d\Z "-333" в "-901-333"
    \z Соответствие должно обнаруживаться в конце строки. -\d\z "-333" в "-901-333"
    \G Совпадение должно происходить в точке, где закончилось предыдущее совпадение, или, если предыдущее совпадение не было, в позиции в строке, где началось сопоставление. \G\(\d\) "(1)" , "(3)" , "(5)" в "(1)(3)(5)[7](9)"
    \b Соответствие должно обнаруживаться на границе между символом \w (алфавитно-цифровым) и символом \W (не алфавитно-цифровым). \b\w+\s\w+\b "them theme" , "them them" в "them theme them them"
    \B Соответствие не должно обнаруживаться на границе \b . \Bend\w*\b "ends" , "ender" в "end sends endure lender"

    Конструкции группирования

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

    Конструкция группирования Описание Шаблон Число соответствий
    ( Subexpression ) Захватывает соответствующую часть выражения и назначает ей порядковый номер, отсчитываемый от единицы. (\w)\1 "ee" в "deep"
    (?< Имя > Subexpression )
    или
    (?' Имя ' Subexpression )
    Выделяет соответствующую часть выражения в именованную группу. (?\w)\k

    "ee" в "deep"
    (?< name1 - name2 > Subexpression )
    или
    (?' name1 - name2 ' Subexpression )
    Задает сбалансированное определение группы. Дополнительные сведения см. в разделе "Сбалансированное определение группы" статьи Конструкции группирования. (((?'Open'\()[^\(\)]*)+((?'Close-Open'\))[^\(\)]*)+)*(?(Open)(?!))$ "((1-3)*(3-1))" в "3+2^((1-3)*(3-1))"
    (?: Subexpression ) Определяет невыделяемую группу. Write(?:Line)? "WriteLine" в "Console.WriteLine()"

    Краткий обзор

    Когда обработчик регулярных выражений попадает в выражение просмотра, он принимает подстроку, достигающую от текущей позиции до начала (lookbehind) или конца (lookahead) исходной строки, а затем выполняется Regex.IsMatch в этой подстроке с использованием шаблона просмотра. Затем успешное выполнение этого вложенного выражения определяется положительным или отрицательным утверждением.

    Обходной путь Имя Функция
    (?=check) Положительный внешний вид Утверждает, что за текущей позицией в строке следует значение "проверка".
    (? <=check) Положительный взгляд сзади Утверждает, что то, что непосредственно перед текущей позицией в строке является "проверка".
    (?!check) Отрицательный внешний вид Утверждает, что то, что сразу после текущей позиции в строке не является "проверка".
    (? Отрицательный взгляд сзади Утверждает, что то, что непосредственно перед текущей позицией в строке не является "проверка".

    После сопоставления атомарные группы не будут повторно оцениваться, даже если оставшаяся часть шаблона завершается ошибкой из-за совпадения. Это может значительно повысить производительность, если квантификаторы находятся в атомарной группе или в оставшейся части шаблона.

    Квантификаторы

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

    Квантификатор Описание Шаблон Число соответствий
    * Соответствует предыдущему элементу ноль или более раз. a.*c "abcbc" в "abcbc" .
    + Соответствует предыдущему элементу один или более раз. "be+" "bee" в "been" , "be" в "bent"
    ? Соответствует предыдущему элементу ноль или один раз. "rai?" "rai" в "rain" .
    < N > Предыдущий элемент повторяется ровно n раз. ",\d" ",043" в "1,043.6" , ",876" , ",543" и ",210" в "9,876,543,210"
    < N ,> Предыдущий элемент повторяется как минимум n раз. "\d" "166" , "29" , "1930"
    < N , М > Предыдущий элемент повторяется как минимум n раз, но не более чем m раз. "\d" "166" , "17668"

    Конструкции обратных ссылок

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

    Конструкция обратных ссылок Описание Шаблон Число соответствий
    \ число Обратная ссылка. Соответствует значению нумерованной части выражения. (\w)\1 "ee" в "seek"
    \k< Имя > Именованная обратная ссылка. Соответствует значению именованного выражения. (?\w)\k

    "ee" в "seek"

    Конструкции чередования

    Конструкции изменения модифицируют регулярное выражение, включая сопоставление по принципу "либо-либо". Такие конструкции состоят из языковых элементов, приведенных в следующей таблице. Дополнительные сведения см. в разделе Конструкции чередования.

    Конструкция изменения Описание Шаблон Число соответствий
    | Соответствует любому элементу, разделенному вертикальной чертой ( | ). th(e|is|at) "the" , "this" в "this is the day."
    (?( Выражение ) Да | Нет )
    или
    (?( Выражение ) Да )
    Соответствует да в случае соответствия шаблона регулярного выражения, определяемого выражением; в противном случае соответствует дополнительной части нет. Выражение интерпретируется как утверждение нулевой ширины.

    Подстановки

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

    Знак Описание Шаблон Шаблон замены Входная строка Результирующая строка
    $ число Замещает часть строки, соответствующую группе число. \b(\w+)(\s)(\w+)\b $3$2$1 "one two" "two one"
    $< Имя > Замещает часть строки, соответствующую именованной группе имя. \b(?\w+)(\s)(?\w+)\b $ $

    "one two" "two one"
    $$ Подставляет литерал "$". \b(\d+)\s?USD $$$1 "103 USD" "$103"
    $& Замещает копией полного соответствия. \$?\d*\.?\d+ **$&** "$1.30" "**$1.30**"
    $` Замещает весь текст входной строки до соответствия. B+ $` "AABBCC" "AAAACC"
    $' Замещает весь текст входной строки после соответствия. B+ $' "AABBCC" "AACCCC"
    $+ Замещает последнюю захваченную группу. B+(C+) $+ "AABBCCDD" "AACCDD"
    $_ Замещает всю входную строку. B+ $_ "AABBCC" "AAAABBCCCC"

    Параметры регулярных выражений

    Можно определить параметры, управляющие интерпретацией шаблона регулярного выражения обработчиком регулярных выражений. Многие из этих параметров можно указать в шаблоне регулярного выражения либо в виде одной или нескольких констант RegexOptions. Этот краткий справочник перечисляет только встраиваемые параметры. Дополнительные сведения о встроенных параметрах и параметрах RegexOptions см. в статье Параметры регулярных выражений.

    Встроенный параметр можно задать двумя способами:

    • При использовании прочей конструкции (?imnsx-imnsx) , где знак минуса (-) перед параметром или набором параметров отключает эти параметры. Например, (?i-mn) включает сопоставление без учета регистра ( i ), отключает многострочный режим ( m ) и отключает захват неименованных групп ( n ). Параметр применяется к шаблону регулярного выражения от точки, в которой определен параметр, и действует либо до конца шаблона, либо до точки, в которой другая конструкция отменяет параметр.
    • С помощью конструкции группирования (?imnsx-imnsx: часть выражения ) , которая определяет параметры для только для указанной группы.

    Механизм регулярных выражений .NET поддерживает следующие встроенные параметры:

    Параметр Описание Шаблон Число соответствий
    i Использовать соответствие без учета регистра. \b(?i)a(?-i)a\w+\b "aardvark" , "aaaAuto" в "aardvark AAAuto aaaAuto Adam breakfast"
    m Использовать многострочный режим. ^ и $ соответствуют началу и концу строки (line), а не началу и концу строки (string). Пример см. в подразделе "Многострочный режим" раздела Параметры регулярных выражений.
    n Не захватывать неименованные группы. Пример см. в подразделе "Только явные захваты" раздела Параметры регулярных выражений.
    s Использовать однострочный режим. Пример см. в подразделе "Однострочный режим" раздела Параметры регулярных выражений.
    x Игнорировать знаки пробела в шаблоне регулярного выражения, не преобразованные в escape-последовательность. \b(?x) \d+ \s \w+ "1 aardvark" , "2 cats" в "1 aardvark 2 cats IV centurions"

    Прочие конструкции

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

    Конструкция Определение Пример
    (?imnsx-imnsx) Устанавливает или отключает такие параметры, как учет регистра в середине шаблона. Дополнительные сведения см. в статье Параметры регулярных выражений. \bA(?i)b\w+\b соответствует "ABA" , "Able" в "ABA Able Act"
    (?# Комментарий ) Встроенное примечание. Примечание заканчивается первой закрывающей скобкой. \bA(?#Matches words starting with A)\w+\b
    # [до конца строки] Комментарий режима X. Примечание начинается от знака # без обратной косой черты и продолжается до конца строки. (?x)\bA\w+\b#Matches words starting with A

    См. также

    • System.Text.RegularExpressions
    • System.Text.RegularExpressions.Regex
    • Регулярные выражения
    • Классы регулярных выражений
    • Краткий справочник по регулярным выражениям (скачать в формате Word)
    • Регулярные выражения — краткий справочник (загрузить в формате PDF)

    Совместная работа с нами на GitHub

    Источник этого содержимого можно найти на GitHub, где также можно создавать и просматривать проблемы и запросы на вытягивание. Дополнительные сведения см. в нашем руководстве для участников.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *