Регулярные выражения (regular expressions) - это формальный язык поиска и осуществления манипуляций с подстроками в текстовой строке, основанный на использовании метасимволов (wildcard characters). Для задания правила поиска используется строка-образец («шаблон» или «маска», англ. pattern), состоящая из символов и метасимволов. Для манипуляций с текстом (например, замены) задаётся строка, которая также может содержать в себе специальные символы.
Таким образом, регулярные выражения представляют собой шаблоны, используемые для сопоставления последовательностей символов в строках. В JavaScript регулярные выражения реализованы отдельным объектом RegExp (используются в его методах exec() и test() ), а также интегрированы в методы match(), replace(), search() и split() объекта String.
Метод | Описание |
exec | Метод RegExp, который выполняет поиск совпадения в строке. Возвращает массив данных. |
test | Метод RegExp, который тестирует совпадение в строке. Возвращает либо истину (true) либо ложь (false). |
match | Метод String, который выполняет поиск совпадения в строке. Возвращает массив данных, либо null если совпадения отсутствуют. |
search | Метод String, который тестирует на совпадение в строке. Возвращает индекс первого совпадения, или -1 если совпадений не будет найдено. |
replace | Метод String, который выполняет поиск совпадения в строке. Заменяет совпавшую подстроку другой подстрокой, переданной как аргумент в этот метод. |
split | Метод String, который использует регулярное выражение или фиксированную строку, чтобы разбить строку на массив подстрок. |
Читайте также Регулярные выражения на https://learn.javascript.ru.
Синтаксис регулярных выражений в JavaScript
Регулярное выражение (regexp, «регэксп» или «регулярка») состоит из шаблона (pattern или «паттерна») и необязательных флагов (flags).
Варианты синтаксиса регулярных выражений:
с помощью конструктора объекта RegExp:
1 |
regexp = new RegExp(pattern , flags); |
с помощью литеральной записи /.../ :
1 2 3 4 5 |
/pattern/flags; // например regexp = /pattern/; // без флагов regexp = /pattern/gmi; // с флагами gmi |
Регулярное выражение regexp в обоих случаях является объектом встроенного класса RegExp.
Отличие создания регулярного выражения с помощью литерала и конструктора:
- Литеральная запись через слеши /.../ не допускает вставок переменных (наподобие возможных в строках через ${...}), в данном случае регулярное выражение является полностью статичным. Слеши используются, когда на момент написания кода точно известно, каким будет регулярное выражение.
- Конструктор new RegExp позволяет создать регулярное выражение из динамически сгенерированной строки.
1 2 3 4 5 6 7 8 9 |
let pattern = prompt("Какой тег вы хотите найти?", "h2"); console.log(pattern); // h2 let regexp = new RegExp(`${pattern}`); console.log(regexp); // /h2/ // или regexp = new RegExp(pattern); console.log(regexp); // /h2/ |
Флаги регулярных выражений
Регулярные выражения могут иметь следующие необязательные флаги (flags), которые размещаются после шаблона (pattern):
1 |
let regexp = /pattern/flags; |
Флаги влияют на поиск следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 |
let str = "Какую Подстроку вы хотите найти?"; // исходная строка const regexp1 = /подстроку/; // без флага i, совпадение найдено не будет console.log(str.replace(regexp1, "ЗАМЕНА")); // Какую Подстроку вы хотите найти? const regexp2 = /подстроку/i; // c флагом i, регистр не учитывается, будет выполнена замена console.log(str.replace(regexp2, "ЗАМЕНА")); // Какую ЗАМЕНА вы хотите найти? // с помощью конструктора let pattern = "подстроку"; let regexp3 = new RegExp(`${pattern}`, 'i'); // формируем паттерн через шаблонную строку console.log(str.replace(regexp3, "ЗАМЕНА")); // Какую ЗАМЕНА вы хотите найти? (с флагом i, с помощью new RegExp() ) |
1 2 3 4 5 6 7 8 9 10 11 12 |
let str = "Анна? Вы сказали Анна?"; // исходная строка const regexp1 = /Анна/; // без флага g console.log(str.replace(regexp1, "Ольга")); // Ольга? Вы сказали Анна?(без флага g найдено только первое совпадение) const regexp2 = /анна/ig; // c флагами i и g console.log(str.replace(regexp2, "Ольга")); // Ольга? Вы сказали Ольга? (с флагами i и g ) // с помощью конструктора let pattern = "Анна"; let regexp3 = new RegExp(`${pattern}`, 'ig'); console.log(str.replace(regexp3, "Ольга")); // Ольга? Вы сказали Ольга? (с флагами i и g , с помощью new RegExp() ) |
Флаг m в регулярных выражениях, переключая поиск в многострочный режим, влияет на поведение следующих символов:
- ^ - начало строки (текста);
- $ - конец строки (текста).
Поиск в начале строки ( ^ ):
1 2 3 4 5 6 7 8 9 10 11 12 |
// исходная строка let str = `1 билет: Анна 2 билета: Анна анна 3 билета: Мария`; // регулярное выражение const regexp1 = /^Анна/im; // поиск с начала строки ( ^ ) c флагами i и m console.log(str.match(regexp1)); // ["анна", index: 29, input: "1 билет: Анна↵2 билета: Анна↵анна 3 билета: Мария", groups: undefined] // регулярное выражение const regexp2 = /^\d/gm; // поиск цифр с начала строки ( ^ ) с флагами g и m console.log(str.match(regexp2)); // (2) ["1", "2"] |
В обычном режиме каретка ( ^ ) – это начало всего текста, а в многострочном – начало каждой строки. «Начало строки» формально означает «сразу после перевода строки», то есть проверка ( ^ ) в многострочном режиме верна на всех позициях, которым предшествует символ перевода строки \n.
Поиск в конце строки ( $ ):
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let str = `1 билет: Анна 2 билета: Анна анна 3 билета: Мария`; // с помощью литерала регулярного выражения const regexp1 = /Анна$/igm; // поиск с конца строки с флагами i, g, m, console.log(str.match(regexp1)); // ["Анна", "Анна"] (найдено 2 совпадения, с флагами i, g, m, с помощью new RegExp() ) // с помощью конструктора let pattern = "анна"; let regexp3 = new RegExp(`${pattern}$`,'igm'); // поиск c конца строки строки ( $ ) console.log(str.match(regexp3)); // ["Анна", "Анна"] (найдено 2 совпадения, с флагами i, g, m, с помощью new RegExp() ) |
Без флага m якорь $ обозначал бы конец всей строки, и была бы найдена только последнее совпадение.
1 2 3 4 5 6 |
str = 'Анна анна АннА'; // исходное выражение let regexp = /анна/y; // регулярное выражение, флаг y - поиск с заданной позиции regexp.lastIndex = 5; // поиск, начиная с 5 позиции в строке console.log( regexp.exec(str) ); // ['анна', index: 5, input: 'Анна анна АннА', groups: undefined] |
Еще пример:
1 2 3 4 5 6 7 8 9 10 11 |
str = 'Анна анна АннА'; let regexp = /\w+/y; // символьный класс \w является сокращением для [a-zA-Z0-9_] regexp.lastIndex = 5; // поиск, начиная с 5 позиции в строке console.log( regexp.exec(str) ); // null (т.к. символьный класс \w является сокращением для [a-zA-Z0-9_], он не найдёт символы, отличающиеся от латиницы (например, кириллические буквы и т.п.) // изменим строку на латиницу str = 'Anna anna AnnA'; regexp.lastIndex = 5; // поиск, начиная с 5 позиции в строке console.log( regexp.exec(str) ); // ['anna', index: 5, input: 'Anna anna AnnA', groups: undefined] |
Использование регулярных выражений в методах объекта RegExp
Метод regexp.exec(str) выполняет поиск совпадения регулярного выражения regexp в указанной строке str. Позволяет осуществлять поиск совпадений, начиная с нужной позиции, заданной в свойстве свойстве lastIndex регулярного выражения.
Если сопоставление не удалось (совпадений нет), метод exec() возвращает null. Если сопоставление успешно (совпадения есть), метод exec() возвращает массив и обновляет свойства объекта регулярного выражения.
Синтаксис метода exec() :
1 |
regexObj.exec(str) |
Возвращаемый массив содержит:
1 |
['substr', '[n]', index: 40, input: 'string', groups: {…}] |
- 'substr' - все совпавшие в строке символы;
- [n] - совпавшие подстроки, заданные в регулярном выражении в круглых скобках (если они присутствуют); количество подстрок не ограничено;
- index - индекс начала совпавшей подстроки в строке (начинается с нуля);
- input - исходная (оригинальная) строка;
- groups - именованные группы; именование задается добавлением ?<name> непосредственно после открытия круглой скобки.
Если целью выполнения является просто определить наличие совпадений, то используйте метод RegExp.prototype.test(), либо метод строки String.prototype.search().
1 2 3 4 5 6 7 8 9 |
let regexp = /дуб\s(зеленый).+?(на)/gi; // регулярное выражение result = regexp.exec("У лукоморья дуб зеленый; Златая цепь на дубе том..."); console.log(result); ['дуб зеленый; Златая цепь на', 'зеленый', 'на', index: 12, input: 'У лукоморья дуб зеленый; Златая цепь на дубе том...', groups: undefined] console.log(result[0]); // "дуб зеленый; Златая цепь на" (полное совпадение с regexp) console.log(result[1]); // "зеленый" (1-я группа в круглых скобках) console.log(result[2]); // "на" (2-я группа в круглых скобках) |
Пример с выводом именованных групп, заданных в регулярном выражении:
1 2 3 4 5 |
str = "У лукоморья 1 (one)\x17дуб зеленый; златая\x99цепь 1 (one) на дубе том."; regexp = /[а-яА-Я]+\s(?<digital>\d)/g; // поиск с флагом g, именованная группа digital console.log(regexp.exec(str)); // ["лукоморья 1", "1", index: 2, input: "У лукоморья 1 (one)дуб зеленый; златаяцепь 1 (one) на дубе том.", groups: {digital: "1"}] |
Если регулярное выражение использует флаг "g", вы можете использовать метод exec() несколько раз для нахождения последовательных сопоставлений в одной и той же строке. При этом метод exec() запоминает позицию после совпадения в свойстве lastIndex регулярного выражения (метод test() также запоминает свойство lastIndex). Поиск начнётся по подстроке строки str, начало которой определяется свойством lastIndex регулярного выражения, например:
Последовательный вызов метода exec() в коде:
1 2 3 4 5 6 7 8 9 |
str = "У лукоморья 1 (one)\x17дуб зеленый; златая\x99цепь 1 (one) на дубе том."; regexp = /[а-яА-Я]+\s\d/g; // поиск с флагом g console.log(regexp.lastIndex); // 0 console.log(regexp.exec(str)); // ['лукоморья 1', index: 2, input: 'У лукоморья 1 (one)дуб зеленый; златаяцепь 1 (one) на дубе том.', groups: undefined] console.log(regexp.lastIndex); // 13 console.log(regexp.exec(str)); // ['цепь 1', index: 40, input: 'У лукоморья 1 (one)дуб зеленый; златаяцепь 1 (one) на дубе том.', groups: undefined] |
Последовательный вызов метода exec() в цикле:
1 2 3 4 5 6 7 8 9 10 11 12 |
str = "У лукоморья 1 (one)\x17дуб зеленый; златая\x99цепь 1 (one) на дубе том."; regexp = /[а-яА-Я]+\s\d/g; // поиск с флагом g let myArray; while ((myArray = regexp.exec(str)) !== null) { let msg = 'Найдено совпадение "' + myArray[0] + '". '; msg += 'Следующий поиск начнётся с позиции ' + regexp.lastIndex; console.log(msg); } // Найдено совпадение "лукоморья 1". Следующий поиск начнётся с позиции 13 // Найдено совпадение "цепь 1". Следующий поиск начнётся с позиции 46 |
Метод regexp.test(str) проверяет есть ли хоть одно совпадение, если да, то возвращает true, иначе - false, например:
1 2 3 4 5 6 7 |
let str = "banana, orange"; let regexp1 = /BaNaNa/; console.log(regexp1.test(str)); // false regexp1 = /BaNaNa/i; // регистронезависимый поиск (флаг i) console.log(regexp1.test(str)); // true |
Использование регулярных выражений в методах строк
Метод str.match(regexp) для строки str возвращает массив совпадений с регулярным выражением regexp, например:
1 2 3 4 5 6 7 8 9 10 |
let str = 'Анна, я зову тебя, Анна!'; let regexp1 = /Анна/; // найдено одно (первое) совпадение console.log(str.match(regexp1)); // ['Анна', index: 0, input: 'Анна, я зову тебя, Анна!', groups: undefined] let regexp2 = /анна/g; // совпадения не найдены console.log(str.match(regexp2)); // null let regexp3 = /анна/gi; // найдены все совпадения (флаги g и i) console.log(str.match(regexp3)); // ['Анна', 'Анна'] |
При отсутствии совпадений возвращается не пустой массив, а null.
Особенности метода str.match(regexp):
- Если регулярное выражение regexp не содержит флаг g, возвращаемый результат будет тем же самым, что и при вызове метода RegExp.exec().
- Если регулярное выражение содержит флаг g, метод вернёт массив, содержащий все совпадения .
- Возвращаемый методом объект (массив) имеет дополнительные свойства:
- input, которое содержит оригинальную строку;
- index, которое представляет индекс совпадения в строке (нумерация с нуля);
- groups , которое содержит массив именованных групп или значение undefined, если именованные группы не были определены.
При поиске всех совпадений (флаг g) метод str.match(regexp) не возвращает скобочные группы.
1 2 3 |
let str = '<h1> <h2> <h3>'; let tags = str.match(/<(.*?)>/g); console.log(tags); // ['<h1>', '<h2>', '<h3>'] |
Результат – массив совпадений, но без деталей о каждом совпадении.
Для получения информации о найденных совпадениях можно использовать метод str.matchAll(regexp).
Отличия метода str.matchAll(regexp) от метода str.match(regexp):
- Возвращает не массив, а перебираемый объект RegExpStringIterator {} (не является псевдомассивом!).
- При поиске с флагом g возвращает каждое совпадение в виде массива со скобочными группами.
- Если совпадений нет, он возвращает не null, а просто пустой перебираемый объект.
Например:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let str = "<h1> <h2> <h3>"; let tags = str.matchAll(/<(.*?)>/gi); // RegExpStringIterator {} (перебираемый объект) tags = Array.from(tags); // RegExpStringIterator {} (преобразуем итерируемый объект в массив) // или так tags = [...str.matchAll(/<(.*?)>/gi)] // (преобразуем итерируемый объект в массив с помощью rest-оператора) console.log(tags); // (3) [Array(2), Array(2), Array(2)] // 0: (2) ["<h1>", "h1", index: 0, input: "<h1> <h2> <h3>", groups: undefined] // 1: (2) ["<h2>", "h2", index: 5, input: "<h1> <h2> <h3>", groups: undefined] // 2: (2) ["<h3>", "h3", index: 10, input: "<h1> <h2> <h3>", groups: undefined] |
В явном преобразовании через Array.from() нет необходимости, если мы перебираем результаты в цикле, например:
1 2 3 4 5 6 7 |
let str = "<h1> <h2> <h3>"; let tags = str.matchAll(/<(.*?)>/gi); // RegExpStringIterator {} for (let key of tags){ console.log(key); // выведет последовательно информацию о всех совпадениях } |
При вызове str.matchAll(regexp) движок JavaScript возвращает перебираемый объект, в котором нет результатов. Поиск совпадений осуществляется по мере того, как мы запрашиваем результаты, например, в цикле. Это позволяет прервать поиск в случае получения нужного результата и освободить ресурсы движка (например, всего в тексте может быть 10 совпадений, а нам нужно всего 3; в цикле после 3-го результата можно использовать break и не искать оставшиеся 7).
Метод str.replace(regexp, replacement) заменяет совпадение с regexp в строке str на replacement , например:
1 2 3 4 5 6 7 |
let str = 'Анна, я зову тебя, Анна!'; let regexp1 = /Анна/; // замена одного (первого) совпадения console.log(str.replace(regexp1,'Ольга')); // Ольга, я зову тебя, Анна! let regexp2 = /анна/gi; // найдены все совпадения (флаг g), причем регистронезависимо (флаг i) console.log(str.replace(regexp2,'Ольга')); // Ольга, я зову тебя, Ольга! |
Отличие replaceAll() и replace():
- Если аргумент regexp является строкой, replaceAll() заменяет все вхождения из regexp на replacement, в то время как replace() только первое вхождение.
- Если аргумент regexp является регулярным выражением без флага g, replaceAll() генерирует исключение TypeError.
1 2 3 4 5 6 |
let str = 'Анна, я зову тебя, Анна!'; console.log(str.replaceAll('Анна','Ольга')); // Ольга, я зову тебя, Ольга! let regexp2 = /анна/gi; // найдены все совпадения (флаг g обязателен), причем регистронезависимо (флаг i) console.log(str.replaceAll(regexp2,'Ольга')); // Ольга, я зову тебя, Ольга! |
В строке замены replacement мы можем использовать специальные комбинации символов для вставки фрагментов совпадения:
Шаблон | Замена | ||||
$$ |
Вставляет символ доллара «$»:
|
||||
$& |
Находит совпадение и добавляет после него подстроку замены:
|
||||
$` |
Вставляет вместо совпадения часть строки, предшествующую этому совпадению:
|
||||
$' |
Вставляет вместо совпадения часть строки, следующую за этим совпадением:
|
||||
$n или $nn |
Символы n или nn являются десятичными цифрами, вставляет n-ную сопоставившуются подгруппу из объекта
Для именованных скобок ссылка будет выглядеть как $<имя>:
|
Специальные символы в регулярных выражениях
Обратите внимание: некоторые специальные символы некорректно работают с символами, отличающимися от латиницы!
Символьные классы |
|||
---|---|---|---|
Символ | Значение | ||
. |
(Точка, десятичная запятая) сопоставляется с любым символом, за исключением символов новой строки: \n, \r, \u2028 или \u2029. Обратите внимание, что флаг многострочности m не изменяет поведение точки: для сопоставления шаблона с несколькими строками используйте набор символов [^] (конечно, если только вам не нужно поддерживать старые версии IE), он сопоставляется с любым символом, включая символы новой строки.
|
||
\d |
Сопоставляется с символом цифры в базовом латинском алфавите. Эквивалентен набору символов [0-9]. Например, шаблоны /\d/ и /[0-9]/ сопоставляются с подстрокой "2" и "1":
|
||
\D |
Сопоставляется с любым символом, который не является цифрой в базовом латинском алфавите. Эквивалентен набору символов [^0-9] (отрицательный набор символов, сопоставляется со всеми символами, кроме заключенных в квадратные скобки; дефис определяет диапазон символов):
|
||
\w |
Сопоставляется с любым алфавитно-цифровым символом из базового латинского алфавита, включая символ подчёркивания. Эквивалентен набору символов [A-Za-z0-9_]:
|
||
\W |
Сопоставляется с любым символом из базового латинского алфавита, не являющимся символом, из которых состоят слова. Эквивалентен набору символов [^A-Za-z0-9_]:
|
||
\s |
Сопоставляется с одиночным пробельным символом, который включает в себя пробел, табуляцию, подачу страницы, перевод строки и другие пробельные символы Юникода. Эквивалентен набору символов [\f\n\r\t\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]:
|
||
\S |
Сопоставляется с одиночным символом, не являющимся пробельным. Эквивалентен набору символов [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000]:
|
||
\t |
Сопоставляется с символом табуляции \u0009:
|
||
\r |
Сопоставляется с символом возврата каретки \u000D (для возвращения позиции устройства к началу строки, обозначается также как CR (carriage return):
|
||
\n |
Сопоставляется с символом перевода строки \u000A:
|
||
\v |
Сопоставляется с символом вертикальной табуляции \u000B. |
||
\f | Сопоставляется с символом подачи страницы. | ||
[\b] | Сопоставляется с символом забоя (стирание предыдущего символа), не перепутайте его с символьным классом границы слова \b. | ||
\0 | Сопоставляется с нулевым символом. Не ставьте за ним другую цифру. | ||
\cX |
Соответствует управляющему символу ASCII, где X является буквой от «A» до «Z». Например, шаблон /\cJ/ сопоставляется с символом перевода строки \x0A (ASCII):
|
||
\xhh | Сопоставляется с символом с кодом hh (две шестнадцатеричные цифры). | ||
\uhhhh | Сопоставляется с символом со значением Юникода hhhh (четыре шестнадцатеричные цифры). | ||
\ |
Обратный слэш указывает для символов:
|
Наборы символов | |||
---|---|---|---|
Символ | Значение | ||
[xyz] |
Набор символов, который сопоставляется с любым из заключённых в квадратные скобки символов. С помощью дефиса можно определить диапазон символов (шаблон [абвгд] означает тоже самое, что и шаблон [а-д]):
|
||
[^xyz] |
Отрицательный или дополнительный набор символов: сопоставляется со всеми символами, что не заключены в квадратные скобки. С помощью дефиса можно определить диапазон символов (шаблон [^абвгд] означает тоже самое, что и шаблон [^а-д].
|
Границы | |||
---|---|---|---|
Символ | Значение | ||
^ |
Сопоставляется c началом ввода. Если установлен флаг многострочности, также сопоставляется с позицией сразу за символом переноса строки:
|
||
$ |
Сопоставляется c концом ввода. Если установлен флаг многострочности, также сопоставляется с позицией сразу перед символом переноса строки:
|
||
\b |
Соответствует пустой строке (не пробелу!) в начале или конце слова. Сопоставляется с границей слова нулевой ширины, например, с позицией между буквой и пробелом (не путайте его с набором символов [\b]):
|
||
\B |
Соответствует пустой строке (не пробелу!) не в начале или конце слова. Сопоставляется с позицией между двумя буквами или двумя пробелами:
|
Группировка и обратные ссылки | |||
---|---|---|---|
Символ | Значение | ||
(x) |
«Захватывающие скобки». Сопоставляется с x и запоминает сопоставление. Совпавшую подстроку можно достать из элементов [1], ..., [n] результирующего массива или из предопределённых свойств $1, ..., $9 объекта RegExp. Захват групп ведёт к снижению производительности. Если вам не нужно повторно ссылаться на захваченную подстроку, лучше использовать скобки без захвата.
|
||
\n |
Где n является целым положительным числом. Обратная ссылка на последнюю сопоставившуюся подстроку в n-ных по счёту круглых скобках в регулярном выражении (нумерация скобок идет слева направо):
|
||
(?:x) |
"Незахватывающие скобки". Сопоставляется с x, но не запоминает сопоставление. Совпавшую подстроку нельзя достать из элементов [1], ..., [n] результирующего массива или из предопределённых свойств $1, ..., $9 объекта RegExp:
|
Квантификатор определяет, сколько раз предшествующее выражение может встречаться после символа, символьного класса или группы.
Квантификатор может относиться более чем к одному символу в регулярном выражении, только если это символьный класс или группа.
Квантификаторы | |||
---|---|---|---|
Символ | Значение | ||
x* |
Сопоставляется с предшествующим элементом x ноль или более раз:
|
||
x+ |
Сопоставляется с предшествующим элементом x один или более раз. Эквивалентен квантификатору {1,}:
|
||
x*? x+? |
Сопоставляется с предшествующим элементом x подобно квантификаторам * и +, описанным выше, однако ищет минимально возможное сопоставление:
|
||
x? |
Сопоставляется с предшествующим элементом x ноль или один раз. Если символ используется сразу после какого-то из квантификаторов *, +, ?, или {}, то он делает этот квантификатор «нежадным» (сопоставление происходит минимально возможное количество раз), в противоположность «жадному» поведению квантификатора по умолчанию (сопоставление происходит максимально возможное количество раз). Также символ используется в квантификаторах предпросмотра (?=), (?!) и (?:).
|
||
x(?=y) |
Сопоставлется с x, только если за x следует y:
|
||
x(?!y) |
Совпадает с x, только если за x не следует y:
|
||
(?<=y)x |
Совпадает с x, только если x предшествует y:
|
||
(?<!y)x |
Совпадает с x, только если x не предшествует y:
|
||
x|y |
Совпадает либо с x, либо с y:
|
||
x{n} |
Совпадает точно с n вхождениями предшествующего элемента x (где n - целое положительное число):
|
||
x{n,} |
Совпадает не менее, чем с n вхождениями предшествующего элемента x (где n - целое положительное число):
|
||
x{n,m} |
Совпадает не менее, чем с n , и не более, чем с m вхождениями предшествующего элемента x (где m и n - целые положительные числа):
|