Spec-Zone.ru › C++

Изменённая грамматика регулярных выражений ECMAScript

На этой странице описана грамматика регулярных выражений, используемая при создании std::basic_regex, если для syntax_option_type задано значение ECMAScript (по умолчанию). Другие поддерживаемые грамматики регулярных выражений см. в разделе syntax_option_type.

Грамматика регулярных выражений ECMAScript 3 в C++ — это грамматика ECMA-262 с изменениями, отмеченными ниже пометкой (только C++).

Обзор

Изменённая грамматика регулярных выражений в основном представляет собой грамматику RegExp ECMAScript с расширением типа POSIX для локалей в разделе ClassAtom. Внесены некоторые уточнения, касающиеся проверок равенства и разбора чисел. Многие приведённые здесь примеры можно проверить в консоли браузера с помощью эквивалентного выражения:

function match(s, re) { return s.match(new RegExp(re)); }

«Нормативные ссылки» в стандарте указывают на ECMAScript 3. Здесь приведена ссылка на спецификацию ECMAScript 5.1, поскольку эта версия отличается от ECMAScript 3 лишь незначительно и доступна в формате HTML. Обзор возможностей диалекта см. в руководстве MDN по RegExp в JavaScript.

Альтернативы

Шаблон регулярного выражения представляет собой одну или несколько Alternative, разделённых оператором дизъюнкции | (иначе говоря, оператор дизъюнкции имеет наименьший приоритет).

Pattern ::

Disjunction

Disjunction ::

Alternative
Alternative | Disjunction

Сначала шаблон пытается пропустить Disjunction и сопоставить левую Alternative, а затем оставшуюся часть регулярного выражения (после дизъюнкции).

Если это не удаётся, он пытается пропустить левую Alternative и сопоставить правую Disjunction (а затем оставшуюся часть регулярного выражения).

Если у левой Alternative, правой Disjunction и оставшейся части регулярного выражения есть точки выбора, все варианты в оставшейся части выражения проверяются до перехода к следующему варианту левой Alternative. Когда варианты левой Alternative исчерпаны, вместо неё проверяется правая Disjunction.

Любые захватывающие скобки внутри пропущенной Alternative создают пустые подсовпадения.

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>

void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}

int main()
{
    show_matches("abcdef", "abc|def");
    show_matches("abc", "ab|abc"); // left Alternative matched first

    // Match of the input against the left Alternative (a) followed
    // by the remained of the regex (c|bc) succeeds, which results
    // in m[1]="a" and m[4]="bc".
    // The skipped Alternatives (ab) and (c) leave their submatches
    // m[3] and m[5] empty.
    show_matches("abc", "((a)|(ab))((c)|(bc))");
}

Вывод:

input=[abcdef], regex=[abc|def]
  prefix=[]
  smatch: m[0]=[abc]
  suffix=[def]
input=[abc], regex=[ab|abc]
  prefix=[]
  smatch: m[0]=[ab]
  suffix=[c]
input=[abc], regex=[((a)|(ab))((c)|(bc))]
  prefix=[]
  smatch: m[0]=[abc] m[1]=[a] m[2]=[a] m[3]=[] m[4]=[bc] m[5]=[] m[6]=[bc]
  suffix=[]

Элементы

Каждая Alternative либо пуста, либо представляет собой последовательность Term (без разделителей между Term)

Alternative ::

[empty]
Alternative Term

Пустая Alternative всегда сопоставляется и не потребляет входные данные.

Соседние Term пытаются одновременно сопоставиться с последовательными частями входных данных.

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

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>

void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}

int main()
{
    show_matches("abcdef", ""); // empty regex is a single empty Alternative
    show_matches("abc", "abc|"); // left Alternative matched first
    show_matches("abc", "|abc"); // left Alternative matched first, leaving abc unmatched
}

Вывод:

input=[abcdef], regex=[]
  prefix=[]
  smatch: m[0]=[]
  suffix=[abcdef]
input=[abc], regex=[abc|]
  prefix=[]
  smatch: m[0]=[abc]
  suffix=[]
input=[abc], regex=[|abc]
  prefix=[]
  smatch: m[0]=[]
  suffix=[abc]

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

  • Каждый Term — это либо Assertion (см. ниже), либо Atom (см. ниже), либо Atom, за которым непосредственно следует Quantifier

Term ::

Assertion
Atom
Atom Quantifier

Каждый Quantifier является либо жадным квантификатором (состоящим только из одного QuantifierPrefix), либо ленивым квантификатором (состоящим из одного QuantifierPrefix, за которым следует вопросительный знак ?).

Quantifier ::

QuantifierPrefix
QuantifierPrefix ?

Каждый QuantifierPrefix задаёт два числа: минимальное и максимальное количество повторений, как показано ниже:

QuantifierPrefix Минимум Максимум
* ноль бесконечность
+ один бесконечность
? ноль один
{ DecimalDigits } значение DecimalDigits значение DecimalDigits
{ DecimalDigits , } значение DecimalDigits бесконечность
{ DecimalDigits , DecimalDigits } значение DecimalDigits перед запятой значение DecimalDigits после запятой

Значения отдельных DecimalDigits получают вызовом std::regex_traits::value(только C++) для каждой цифры.

Atom, за которым следует Quantifier, повторяется указанное в Quantifier число раз. Quantifier может быть ленивым: в этом случае шаблон Atom повторяется как можно меньше раз, но так, чтобы оставшаяся часть регулярного выражения всё ещё сопоставлялась. Либо он может быть жадным: в этом случае шаблон Atom повторяется как можно больше раз, но так, чтобы оставшаяся часть регулярного выражения всё ещё сопоставлялась.

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

Если у Atom и оставшейся части регулярного выражения есть точки выбора, сначала Atom сопоставляется максимально возможное число раз (или минимально возможное, если он ленивый). Все варианты оставшейся части регулярного выражения проверяются до перехода к следующему варианту последнего повторения Atom. Все варианты последнего (n-го) повторения Atom проверяются до перехода к следующему варианту предпоследнего ((n–1)-го) повторения Atom; в этот момент может оказаться, что теперь возможно большее или меньшее число повторений Atom. Эти варианты исчерпываются (снова начиная с минимально или максимально возможного числа повторений) до перехода к следующему варианту (n-1)-го повторения Atom и так далее.

Захваты Atom очищаются при каждом его повторении (см. пример "(z)((a+)?(b+)?(c))*" ниже)

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>

void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}

int main()
{
    // greedy match, repeats [a-z] 4 times
    show_matches("abcdefghi", "a[a-z]{2,4}");
    // non-greedy match, repeats [a-z] 2 times
    show_matches("abcdefghi", "a[a-z]{2,4}?");

    // Choice point ordering for quantifiers results in a match
    // with two repetitions, first matching the substring "aa",
    // second matching the substring "ba", leaving "ac" not matched
    // ("ba" appears in the capture clause m[1])
    show_matches("aabaac", "(aa|aabaac|ba|b|c)*");

    // Choice point ordering for quantifiers makes this regex 
    // calculate the greatest common divisor between 10 and 15
    // (the answer is 5, and it populates m[1] with "aaaaa")
    show_matches("aaaaaaaaaa,aaaaaaaaaaaaaaa", "^(a+)\\1*,\\1+$");

    // the substring "bbb" does not appear in the capture clause m[4]
    // because it is cleared when the second repetition of the atom
    // (a+)?(b+)?(c) is matching the substring "ac"
    // NOTE: gcc gets this wrong - it does not correctly clear the
    // matches[4] capture group as required by ECMA-262 21.2.2.5.1,
    // and thus incorrectly captures "bbb" for that group.
    show_matches("zaacbbbcac", "(z)((a+)?(b+)?(c))*");
}

Вывод:

input=[abcdefghi], regex=[a[a-z]{2,4}]
  prefix=[]
  smatch: m[0]=[abcde]
  suffix=[fghi]
input=[abcdefghi], regex=[a[a-z]{2,4}?]
  prefix=[]
  smatch: m[0]=[abc]
  suffix=[defghi]
input=[aabaac], regex=[(aa|aabaac|ba|b|c)*]
  prefix=[]
  smatch: m[0]=[aaba] m[1]=[ba]
  suffix=[ac]
input=[aaaaaaaaaa,aaaaaaaaaaaaaaa], regex=[^(a+)\1*,\1+$]
  prefix=[]
  smatch: m[0]=[aaaaaaaaaa,aaaaaaaaaaaaaaa] m[1]=[aaaaa]
  suffix=[]
input=[zaacbbbcac], regex=[(z)((a+)?(b+)?(c))*]
  prefix=[]
  smatch: m[0]=[zaacbbbcac] m[1]=[z] m[2]=[ac] m[3]=[a] m[4]=[] m[5]=[c] 
  suffix=[]

Утверждения

Assertion сопоставляют условия, а не подстроки входной строки. Они никогда не потребляют символы входных данных. Каждое Assertion представляет собой один из следующих вариантов

Assertion ::

^
$
\ b
\ B
( ? = Disjunction )
( ? ! Disjunction )

Утверждение ^ (начало строки) сопоставляется с

1) позицией сразу после символа LineTerminator (поддержка может отсутствовать)(до C++17) (гарантируется только при включённом параметре std::regex_constants::multiline(только C++))(начиная с C++17)
2) началом входных данных (если не включён параметр std::regex_constants::match_not_bol(только C++))

Утверждение $ (конец строки) сопоставляется с

1) позицией символа LineTerminator (поддержка может отсутствовать)(до C++17)(гарантируется только при включённом параметре std::regex_constants::multiline(только C++))(начиная с C++17)
2) концом входных данных (если не включён параметр std::regex_constants::match_not_eol(только C++))

В двух приведённых выше утверждениях и в атоме . ниже LineTerminator — это один из следующих четырёх символов: U+000A (\n или перевод строки), U+000D (\r или возврат каретки), U+2028 (разделитель строк) или U+2029 (разделитель абзацев)

Утверждение \b (граница слова) сопоставляется с

1) началом слова (текущий символ — буква, цифра или подчёркивание, а предыдущий символ — нет)
2) концом слова (текущий символ — не буква, не цифра и не подчёркивание, а предыдущий символ — один из них)
3) началом входных данных, если первый символ — буква, цифра или подчёркивание (если не включён параметр std::regex_constants::match_not_bow(только C++))
4) концом входных данных, если последний символ — буква, цифра или подчёркивание (если не включён параметр std::regex_constants::match_not_eow(только C++))

Утверждение \B (не-граница слова) сопоставляется со всем, КРОМЕ следующего:

1) начала слова (текущий символ — буква, цифра или подчёркивание, а предыдущий символ не является одним из них или отсутствует)
2) конца слова (текущий символ — не буква, не цифра и не подчёркивание (или сопоставление находится в конце входных данных), а предыдущий символ — один из них)

Утверждение ( ? = Disjunction ) (проверка вперёд с нулевой шириной и положительным условием) сопоставляется, если Disjunction сопоставлялась бы с входными данными в текущей позиции

Утверждение ( ? ! Disjunction ) (проверка вперёд с нулевой шириной и отрицательным условием) сопоставляется, если Disjunction НЕ сопоставлялась бы с входными данными в текущей позиции.

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

ECMAScript запрещает возврат с пересмотром в дизъюнкции Lookahead, что влияет на поведение обратных ссылок из оставшейся части регулярного выражения на положительную проверку вперёд (см. пример ниже). Обратные ссылки на отрицательную проверку вперёд из оставшейся части регулярного выражения всегда не определены (так как дизъюнкция проверки вперёд должна завершиться неудачей, чтобы продолжить сопоставление).

Примечание: проверки вперёд можно использовать для создания логического И нескольких регулярных выражений (см. пример ниже).

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>

void show_matches(const std::string& in, const std::string& re)
{
    std::smatch m;
    std::regex_search(in, m, std::regex(re));
    if (!m.empty())
    {
        std::cout << "input=[" << in << "], regex=[" << re << "]\n  "
                     "prefix=[" << m.prefix() << "]\n  smatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::cout << "m[" << n << "]=[" << m[n] << "] ";
        std::cout << "\n  suffix=[" << m.suffix() << "]\n";
    }
    else
        std::cout << "input=[" << in << "], regex=[" << re << "]: NO MATCH\n";
}

int main()
{
    // matches the a at the end of input
    show_matches("aaa", "a$");

    // matches the o at the end of the first word
    show_matches("moo goo gai pan", "o\\b");

    // the lookahead matches the empty string immediately after the first b
    // this populates m[1] with "aaa" although m[0] is empty
    show_matches("baaabac", "(?=(a+))");

    // because backtracking into lookaheads is prohibited, 
    // this matches aba rather than aaaba
    show_matches("baaabac", "(?=(a+))a*b\\1");

    // logical AND via lookahead: this password matches IF it contains
    // at least one lowercase letter
    // AND at least one uppercase letter
    // AND at least one punctuation character
    // AND be at least 6 characters long
    show_matches("abcdef", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}");
    show_matches("aB,def", "(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}");
}

Вывод:

input=[aaa], regex=[a$]
  prefix=[aa]
  smatch: m[0]=[a] 
  suffix=[]
input=[moo goo gai pan], regex=[o\b]
  prefix=[mo]
  smatch: m[0]=[o] 
  suffix=[ goo gai pan]
input=[baaabac], regex=[(?=(a+))]
  prefix=[b]
  smatch: m[0]=[] m[1]=[aaa] 
  suffix=[aaabac]
input=[baaabac], regex=[(?=(a+))a*b\1]
  prefix=[baa]
  smatch: m[0]=[aba] m[1]=[a] 
  suffix=[c]
input=[abcdef], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]: NO MATCH
input=[aB,def], regex=[(?=.*[[:lower:]])(?=.*[[:upper:]])(?=.*[[:punct:]]).{6,}]
  prefix=[]
  smatch: m[0]=[aB,def] 
  suffix=[]

Атомы

Atom может быть одним из следующих вариантов:

Atom ::

PatternCharacter
.
\ AtomEscape
CharacterClass
( Disjunction )
( ? : Disjunction )

где AtomEscape ::

DecimalEscape
CharacterEscape
CharacterClassEscape

Разные типы атомов обрабатываются по-разному.

Подвыражения

Atom ( Disjunction ) — это помеченное подвыражение: оно выполняет Disjunction и сохраняет копию входной подстроки, потреблённой Disjunction, в массиве подсовпадений по индексу, соответствующему числу открывающих левых скобок ( помеченных подвыражений, встреченных к этому моменту во всём регулярном выражении.

Помимо возвращения в std::match_results, захваченные подсовпадения доступны как обратные ссылки (\1, \2, ...) и могут использоваться в регулярных выражениях. Обратите внимание: std::regex_replace использует $ вместо \ для обратных ссылок ($1, $2, ...), как и String.prototype.replace (ECMA-262, часть 15.5.4.11).

Atom ( ? : Disjunction ) (непомеченное подвыражение) просто выполняет Disjunction и не сохраняет результаты в подсовпадении. Это группировка исключительно лексического уровня.

Обратные ссылки

DecimalEscape ::

DecimalIntegerLiteral [lookahead ∉ DecimalDigit]

Если за \ следует десятичное число N, первая цифра которого не равна 0, escape-последовательность считается обратной ссылкой. Значение N получают вызовом std::regex_traits::value(только C++) для каждой цифры и объединением результатов с использованием арифметики по основанию 10. Если N больше общего числа левых захватывающих скобок во всём регулярном выражении, возникает ошибка.

Когда обратная ссылка \N встречается как Atom, она сопоставляется с той же подстрокой, которая в данный момент хранится в N-м элементе массива подсовпадений.

Десятичная escape-последовательность \0 НЕ является обратной ссылкой: это escape-последовательность символа, представляющая символ NUL. За ней не может следовать десятичная цифра.

Как отмечалось выше, std::regex_replace использует $ вместо \ для обратных ссылок ($1, $2, ...).

Сопоставление с одним символом

Atom . сопоставляется с любым одним символом входной строки, кроме LineTerminator (U+000D, U+000A, U+2029 или U+2028), и потребляет его

Atom PatternCharacter, где PatternCharacter — это любой SourceCharacter, КРОМЕ символов ^ $ \ . * + ? ( ) [ ] { } |, сопоставляется с одним символом входных данных и потребляет его, если он равен этому PatternCharacter.

Равенство для этого и всех остальных вариантов сопоставления с одним символом определяется следующим образом:

1) Если задано std::regex_constants::icase, символы считаются равными, если равны возвращаемые значения std::regex_traits::translate_nocase (только C++).
2) Иначе, если задано std::regex_constants::collate, символы считаются равными, если равны возвращаемые значения std::regex_traits::translate (только C++).
3) В противном случае символы считаются равными, если operator== возвращает true.

Каждый Atom, состоящий из символа экранирования \, за которым следует CharacterEscape, а также специальная десятичная escape-последовательность \0, сопоставляется с одним символом входных данных и потребляет его, если он равен символу, представленному CharacterEscape. Распознаются следующие escape-последовательности символов:

CharacterEscape ::

ControlEscape
c ControlLetter
HexEscapeSequence
UnicodeEscapeSequence
IdentityEscape

Здесь ControlEscape — один из следующих пяти символов: f n r t v

ControlEscape Кодовая единица Название
f U+000C перевод страницы
n U+000A перевод строки
r U+000D возврат каретки
t U+0009 горизонтальная табуляция
v U+000B вертикальная табуляция

ControlLetter — любая строчная или прописная буква ASCII; эта escape-последовательность символа сопоставляется с символом, кодовая единица которого равна остатку от деления значения кодовой единицы ControlLetter на 32. Например, \cD и \cd обе сопоставляются с кодовой единицей U+0004 (EOT), поскольку 'D' имеет значение U+0044 и 0x44 % 32 == 4, а 'd' — U+0064 и 0x64 % 32 == 4.

HexEscapeSequence — это буква x, за которой следуют ровно две цифры HexDigit (где HexDigit — один из символов 0 1 2 3 4 5 6 7 8 9 a b c d e f A B C D E F). Эта escape-последовательность символа сопоставляется с символом, кодовая единица которого равна числовому значению двухзначного шестнадцатеричного числа.

UnicodeEscapeSequence — это буква u, за которой следуют ровно четыре цифры HexDigit. Эта escape-последовательность символа сопоставляется с символом, кодовая единица которого равна числовому значению этого четырёхзначного шестнадцатеричного числа. Если значение не помещается в CharT данного std::basic_regex, возникает исключение std::regex_error (только C++).

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

#include <cstddef>
#include <iostream>
#include <regex>
#include <string>

void show_matches(const std::wstring& in, const std::wstring& re)
{
    std::wsmatch m;
    std::regex_search(in, m, std::wregex(re));
    if (!m.empty())
    {
        std::wcout << L"input=[" << in << L"], regex=[" << re << L"]\n  "
                      L"prefix=[" << m.prefix() << L"]\n  wsmatch: ";
        for (std::size_t n = 0; n < m.size(); ++n)
            std::wcout << L"m[" << n << L"]=[" << m[n] << L"] ";
        std::wcout << L"\n  suffix=[" << m.suffix() << L"]\n";
    }
    else
        std::wcout << L"input=[" << in << "], regex=[" << re << L"]: NO MATCH\n";
}

int main()
{
    // Most escapes are similar to C++, save for metacharacters. You will have to
    // double-escape or use raw strings on the slashes though.
    show_matches(L"C++\\", LR"(C\+\+\\)");

    // Escape sequences and NUL.
    std::wstring s(L"ab\xff\0cd", 5);
    show_matches(s, L"(\\0|\\u00ff)");

    // No matching for non-BMP Unicode is defined, because ECMAScript uses UTF-16
    // atoms. Whether this emoji banana matches can be platform dependent:
    // These need to be wide-strings!
    show_matches(L"\U0001f34c", L"[\\u0000-\\ufffe]+");
}

Возможный вывод:

input=[C++\], regex=[C\+\+\\]
  prefix=[]
  wsmatch: m[0]=[C++\]
  suffix=[]
input=[ab?c], regex=[(\0{{!}}\u00ff)]
  prefix=[ab]
  wsmatch: m[0]=[?] m[1]=[?]
  suffix=[c]
input=[?], regex=[[\u0000-\ufffe]+]: NO MATCH

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

Atom может представлять класс символов, то есть сопоставляться с одним символом и потреблять его, если он принадлежит одной из предопределённых групп символов.

Класс символов можно задать с помощью escape-последовательности класса символов:

Atom :: \

CharacterClassEscape

или непосредственно

Atom ::

CharacterClass

Escape-последовательности классов символов — это сокращённые обозначения некоторых распространённых классов символов:

CharacterClassEscape Выражение ClassName(только C++) Значение
d [[:digit:]] цифры
D [^[:digit:]] символы, не являющиеся цифрами
s [[:space:]] пробельные символы
S [^[:space:]] символы, не являющиеся пробельными
w [_[:alnum:]] буквенно-цифровые символы и символ _
W [^_[:alnum:]] символы, кроме буквенно-цифровых и _

Точное значение каждой из этих escape-последовательностей классов символов в C++ определяется через именованные классы символов, зависящие от локали, а не явным перечислением допустимых символов, как в ECMAScript.

CharacterClass — это заключённая в квадратные скобки последовательность ClassRanges, перед которой может находиться оператор отрицания ^. Если она начинается с ^, этот Atom сопоставляется с любым символом, НЕ входящим в множество символов, представленное объединением всех ClassRanges. В противном случае этот Atom сопоставляется с любым символом, входящим в множество символов, представленное объединением всех ClassRanges.

CharacterClass ::

[ [ lookahead ∉ {^}] ClassRanges ]
[ ^ ClassRanges ]

ClassRanges ::

[пусто]
NonemptyClassRanges

NonemptyClassRanges ::

ClassAtom
ClassAtom NonemptyClassRangesNoDash
ClassAtom - ClassAtom ClassRanges

Если непустой диапазон класса имеет вид ClassAtom - ClassAtom, он сопоставляется с любым символом диапазона, определённого следующим образом: (только C++)

Первый ClassAtom должен сопоставляться с одним элементом сортировки c1, а второй ClassAtom — с одним элементом сортировки c2. Чтобы проверить, сопоставляется ли входной символ c с этим диапазоном, выполняются следующие действия:

1) Если std::regex_constants::collate выключен, сопоставление символа выполняется прямым сравнением кодовых точек: c сопоставляется, если c1 <= c && c <= c2
1) В противном случае (если включён std::regex_constants::collate):
1) Если включён std::regex_constants::icase, все три символа (c, c1 и c2) передаются std::regex_traits::translate_nocase
2) В противном случае (если std::regex_constants::icase не задан), все три символа (c, c1 и c2) передаются std::regex_traits::translate
2) Полученные строки сравниваются с помощью std::regex_traits::transform; символ c сопоставляется, если transformed c1 <= transformed c && transformed c <= transformed c2

Символ - трактуется буквально, если он

  • является первым или последним символом ClassRanges
  • находится в начале или конце описания диапазона, в котором символы разделены дефисом
  • непосредственно следует за описанием диапазона, в котором символы разделены дефисом.
  • экранирован обратной косой чертой как CharacterEscape

NonemptyClassRangesNoDash ::

ClassAtom
ClassAtomNoDash NonemptyClassRangesNoDash
ClassAtomNoDash - ClassAtom ClassRanges

ClassAtom ::

-
ClassAtomNoDash
ClassAtomExClass(только C++)
ClassAtomCollatingElement(только C++)
ClassAtomEquivalence(только C++)

ClassAtomNoDash ::

SourceCharacter, кроме символов \ or ] or -
\ ClassEscape

Каждый ClassAtomNoDash представляет один символ — либо SourceCharacter без изменений, либо экранированный следующим образом:

ClassEscape ::

DecimalEscape
b
CharacterEscape
CharacterClassEscape

Специальный ClassEscape \b создаёт набор символов, сопоставляющийся с кодовой единицей U+0008 (забой). За пределами CharacterClass это граница слова — Assertion.

Использование \B и любой обратной ссылки (DecimalEscape, отличной от нуля) внутри CharacterClass является ошибкой.

В некоторых случаях символы - и ] необходимо экранировать, чтобы трактовать их как атомы. Другие символы, имеющие специальное значение вне CharacterClass, например * или ?, экранировать не требуется.

Классы символов на основе POSIX

Эти классы символов являются расширением грамматики ECMAScript и эквивалентны классам символов в регулярных выражениях POSIX.

ClassAtomExClass(только C++) :: [:

ClassName :]

Представляет все символы, принадлежащие именованному классу символов ClassName. Имя допустимо, только если std::regex_traits::lookup_classname возвращает для него ненулевое значение. Как описано в std::regex_traits::lookup_classname, гарантированно распознаются следующие имена: alnum, alpha, blank, cntrl, digit, graph, lower, print, punct, space, upper, xdigit, d, s, w. Дополнительные имена могут предоставляться системными локалями (например, jdigit или jkanji в японском языке) либо реализовываться в виде пользовательского расширения.

ClassAtomCollatingElement(только C++) :: [.

ClassName .]

Представляет именованный элемент сортировки, который может обозначать один символ или последовательность символов, сортируемую как единое целое в соответствии с используемой локалью, например [.tilde.] или [.ch.] в чешском языке. Имя допустимо, только если std::regex_traits::lookup_collatename не является пустой строкой.

При использовании std::regex_constants::collate элементы сортировки всегда можно использовать в качестве концов диапазона (например, [[.dz.]-g] в венгерском языке).

ClassAtomEquivalence(только C++) :: [=

ClassName =]

Представляет все символы, принадлежащие тому же классу эквивалентности, что и именованный элемент сортировки, то есть все символы с тем же первичным ключом сортировки, что и у элемента сортировки ClassName. Имя допустимо, только если std::regex_traits::lookup_collatename для этого имени не является пустой строкой и значение, возвращаемое std::regex_traits::transform_primary для результата вызова std::regex_traits::lookup_collatename, также не является пустой строкой.

Первичный ключ сортировки — это ключ, не учитывающий регистр, диакритические знаки или настройки сортировки, специфичные для локали; поэтому, например, [[=a=]] сопоставляется с любым из символов: a, À, Á, Â, Ã, Ä, Å, A, à, á, â, ã, ä and å.

ClassName(только C++) ::

ClassNameCharacter
ClassNameCharacter ClassName

ClassNameCharacter(только C++) ::

SourceCharacter, кроме символов . = :

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/regex/ecmascript

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API