Namespaces
Variants

Modified ECMAScript regular expression grammar

From ru.cppreference.net

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

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

Содержание

Обзор

Модифицированная грамматика регулярных выражений в основном представляет собой грамматику ECMAScript RegExp с POSIX-подобным расширением для локалей в ClassAtom . Внесены некоторые уточнения относительно проверок равенства и разбора чисел. Для многих примеров здесь вы можете попробовать эквивалент в консоли вашего браузера:

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

"Нормативные ссылки" в стандарте указывают на ECMAScript 3. Мы ссылаемся на спецификацию ECMAScript 5.1 здесь, поскольку это версия с незначительными изменениями по сравнению с ECMAScript 3, и она также имеет HTML-версию. Смотрите Руководство MDN по JavaScript RegExp для обзора особенностей диалекта.

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

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

Pattern ::

Дизъюнкция

Дизъюнкция ::

Альтернатива
Альтернатива | Дизъюнкция

Паттерн сначала пытается пропустить Disjunction и сопоставить левую Alternative с последующей частью регулярного выражения (после Disjunction).

Если это не удается, он пытается пропустить левый 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"); // сначала найдено левое альтернативное выражение
    // Сопоставление ввода с левым альтернативным выражением (a), за которым
    // следует остаток регулярного выражения (c|bc), завершается успешно, что приводит
    // к m[1]="a" и m[4]="bc".
    // Пропущенные альтернативные выражения (ab) и (c) оставляют свои подсовпадения
    // m[3] и m[5] пустыми.
    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 ами)

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

[пусто]
Альтернативный Термин

Пустой Альтернативный всегда соответствует и не потребляет никакой ввод.

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

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

#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", ""); // пустое регулярное выражение представляет собой единственную пустую альтернативу
    show_matches("abc", "abc|"); // сначала сопоставляется левая альтернатива
    show_matches("abc", "|abc"); // сначала сопоставляется левая альтернатива, оставляя abc несопоставленным
}

Вывод:

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]

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

  • Каждый Терм является либо Утверждением (см. ниже), либо Атомом (см. ниже), либо Атомом , за которым непосредственно следует Квантор

Термин ::

Утверждение
Атом
Атом Квантор

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

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

КванторныйПрефикс
КванторныйПрефикс ?

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

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

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

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

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

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

Захваты Atom' a очищаются каждый раз, когда он повторяется (см. пример "(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()
{
    // жадное совпадение, повторяет [a-z] 4 раза
    show_matches("abcdefghi", "a[a-z]{2,4}");
    // нежадное совпадение, повторяет [a-z] 2 раза
    show_matches("abcdefghi", "a[a-z]{2,4}?");
    // Порядок точек выбора для квантификаторов приводит к совпадению
    // с двумя повторениями, первое соответствует подстроке "aa",
    // второе соответствует подстроке "ba", оставляя "ac" несовпавшим
    // ("ba" появляется в группе захвата m[1])
    show_matches("aabaac", "(aa|aabaac|ba|b|c)*");
    // Порядок точек выбора для квантификаторов позволяет этому регулярному выражению
    // вычислить наибольший общий делитель между 10 и 15
    // (ответ 5, и оно заполняет m[1] значением "aaaaa")
    show_matches("aaaaaaaaaa,aaaaaaaaaaaaaaa", "^(a+)\\1*,\\1+$");
    // подстрока "bbb" не появляется в группе захвата m[4]
    // потому что она очищается, когда второе повторение атома
    // (a+)?(b+)?(c) соответствует подстроке "ac"
    // ПРИМЕЧАНИЕ: gcc ошибается здесь - он не очищает правильно
    // группу захвата matches[4] как требуется по ECMA-262 21.2.2.5.1,
    // и поэтому неправильно захватывает "bbb" для этой группы.
    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=[]

Утверждения

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

Утверждение ::

^
$
\ b
\ B
( ? = Дизъюнкция )
( ? ! Дизъюнкция )

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

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++ only) )

В двух приведенных выше утверждениях и в атоме . ниже, 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++ only) не активирован)

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

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

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

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

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

ECMAScript запрещает возврат в опережающие проверки (lookahead Disjunctions), что влияет на поведение обратных ссылок (backreferences) в положительной опережающей проверке (positive lookahead) из оставшейся части регулярного выражения (см. пример ниже). Обратные ссылки в отрицательной опережающей проверке (negative 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()
{
    // соответствует 'a' в конце входной строки
    show_matches("aaa", "a$");
    // соответствует 'o' в конце первого слова
    show_matches("moo goo gai pan", "o\\b");
    // опережающая проверка соответствует пустой строке сразу после первой 'b'
    // это заполняет m[1] значением "aaa", хотя m[0] пуст
    show_matches("baaabac", "(?=(a+))");
    // поскольку возврат в опережающие проверки запрещен,
    // это соответствует 'aba', а не 'aaaba'
    show_matches("baaabac", "(?=(a+))a*b\\1");
    // логическое И через опережающую проверку: этот пароль соответствует, ЕСЛИ он содержит
    // как минимум одну строчную букву
    // И как минимум одну заглавную букву
    // И как минимум один знак пунктуации
    // И имеет длину не менее 6 символов
    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 ::

СимволШаблона
.
\ ЭкранированиеАтома
КлассСимволов
( Дизъюнкция )
( ? : Дизъюнкция )

где AtomEscape ::

DecimalEscape
CharacterEscape
CharacterClassEscape

Различные виды атомов оцениваются по-разному.

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

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

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

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

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

DecimalEscape ::

DecimalIntegerLiteral [ lookahead ∉ DecimalDigit ]

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

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

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

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

Совпадения одиночных символов

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

Атом 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 , состоящий из escape-символа \ , за которым следует CharacterEscape , а также специальный DecimalEscape \0 , сопоставляется и потребляет один символ из входных данных, если он равен символу, представленному CharacterEscape . Распознаются следующие escape-последовательности символов:

CharacterEscape ::

ControlEscape
c ControlLetter
HexEscapeSequence
UnicodeEscapeSequence
IdentityEscape

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

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

ControlLetter — это любая строчная или заглавная буква ASCII, и эта управляющая последовательность соответствует символу, кодовая единица которого равна остатку от деления значения кодовой единицы 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-последовательность соответствует символу, кодовая единица которого равна числовому значению этого четырёхзначного шестнадцатеричного числа. Если значение не помещается в std::basic_regex 's CharT , выбрасывается 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()
{
    // Большинство экранирований аналогичны C++, за исключением метасимволов. Вам придется
    // удваивать экранирование или использовать сырые строки для слешей.
    show_matches(L"C++\\", LR"(C\+\+\\)");
    // Escape-последовательности и NUL.
    std::wstring s(L"ab\xff\0cd", 5);
    show_matches(s, L"(\\0|\\u00ff)");
    // Сопоставление для не-BMP Unicode не определено, потому что ECMAScript использует UTF-16
    // атомы. Может ли этот эмодзи банан совпасть, может зависеть от платформы:
    // Это должны быть широкие строки!
    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

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

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

Класс символов может быть введён через escape-последовательность класса символов:

Atom ::

\ ЭкранированиеКлассаСимволов

или напрямую

Atom ::

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

Символьные классы с escape-последовательностями являются сокращениями для некоторых распространённых символьных классов, как показано далее:

CharacterClassEscape ClassName expression (только 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
  • начальный или конечный ClassAtom в спецификации диапазона через дефис
  • непосредственно следует за спецификацией диапазона через дефис
  • экранируется обратной косой чертой как CharacterEscape

NonemptyClassRangesNoDash ::

ClassAtom
ClassAtomNoDash NonemptyClassRangesNoDash
ClassAtomNoDash - ClassAtom ClassRanges

ClassAtom ::

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

ClassAtomNoDash ::

SourceCharacter но не один из \ или ] или -
\ ClassEscape

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

ClassEscape ::

DecimalEscape
b
CharacterEscape
CharacterClassEscape

Специальная ClassEscape \b создает набор символов, соответствующий кодовой единице U+0008 (backspace). За пределами 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 но не один из . = :