Skip to content

Instantly share code, notes, and snippets.

@alizhdanov
Last active October 11, 2017 07:37
Show Gist options
  • Save alizhdanov/dc4227f40a7adb3ae89eeafbe24400b5 to your computer and use it in GitHub Desktop.
Save alizhdanov/dc4227f40a7adb3ae89eeafbe24400b5 to your computer and use it in GitHub Desktop.

Regexp - шпаргалка

Синтаксис для создания

var regexp = new RegExp("шаблон", "флаги");
// or
var regexp = /шаблон/; // без флагов
var regexp = /шаблон/gmi; // с флагами gmi

Слеши "/" говорят JavaScript о том, что это регулярное выражение. Они играют здесь ту же роль, что и кавычки для обозначения строк.

Флаги

i

Если этот флаг есть, то регэксп ищет независимо от регистра, то есть не различает между А и а.

g

Если этот флаг есть, то регэксп ищет все совпадения, иначе – только первое.

m

Многострочный режим.

Методы RegExp и String

str.search(reg)

Возвращает позицию первого совпадения или -1, если ничего не найдено.

var str = "Люблю регэкспы я, но странною любовью";

str.search( /лю/i ) // 0
str.search( /но/i ) // 18
str.search( /робот/i ) // 18

Ограничение метода search – он всегда ищет только первое совпадение.

str.match(reg) без флага g

Находит только одно, первое совпадение. Результат вызова – это массив, состоящий из этого совпадения, с дополнительными свойствами index – позиция, на которой оно обнаружено и input – строка, в которой был поиск.

var str = "ОЙ-Ой-ой";

str.match( /ой/i ); // ["ОЙ", index: 0, input: "ОЙ-Ой-ой"]

Если часть шаблона обозначена скобками, то она станет отдельным элементом массива.

var str = "javascript - это такой язык";

str.match( /JAVA(SCRIPT)/i ); // ["javascript", "script", index: 0, input: "javascript - это такой язык"]

str.match(reg) с флагом g

Возвращает обычный массив из всех совпадений. Никаких дополнительных свойств у массива в этом случае нет, скобки дополнительных элементов не порождают.

var str = "ОЙ-Ой-ой";

str.match( /ой/ig ); // ["ОЙ", "Ой", "ой"]
str.match( /йо/ig ); // null - нет совпадений

В случае, если совпадений не было, match возвращает null Обратите внимание, это важно – если match не нашёл совпадений, он возвращает не пустой массив, а именно null.

Это важно иметь в виду, чтобы не попасть в такую ловушку:

var str = "Ой-йой-йой";

// результат match не всегда массив!
str.match(/лю/gi).length // ошибка! нет свойства length у null

str.split(reg|substr, limit)

Разбивает строку в массив по разделителю – регулярному выражению regexp или подстроке substr.

'12-34-56'.split(/-/) // [12, 34, 56]

str.replace(reg, str|func)

Простейшее применение

// заменить дефис на двоеточие
'12-34-56'.replace("-", ":") // 12:34-56

При вызове со строкой замены replace всегда заменяет только первое совпадение.

Чтобы заменить все совпадения, нужно использовать для поиска не строку "-", а регулярное выражение /-/g, причём обязательно с флагом g:

// заменить дефис на двоеточие
'12-34-56'.replace( /-/g, ":" )  // 12:34:56

В строке для замены можно использовать специальные символы (здесь подробнее):

var str = "Василий Пупкин";
str.replace(/(Василий) (Пупкин)/, '$2, $1') // Пупкин, Василий

var str = "Василий Пупкин";
str.replace(/Василий Пупкин/, 'Великий $&!') // Великий Василий Пупкин!

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

"ОЙ-Ой-ой".replace(/ой/gi, function(match, (тут могут быть скобочные совпадения), offset, string) {
  return 'Слоово ' + match + ' найденно на позиции ' + offset + ' в строке ' + string;
});

regexp.test(str)

Метод test проверяет, есть ли хоть одно совпадение в строке str. Возвращает true/false.

var str = "Люблю регэкспы я, но странною любовью";

/лю/i.test(str) // true
/помидор/i.test(str) // false

regexp.exec(str)

Метод ведёт себя по-разному, в зависимости от того, есть ли у регэкспа флаг g.

Если флага g нет, то regexp.exec(str) ищет и возвращает первое совпадение, является полным аналогом вызова str.match(reg). Если флаг g есть, то вызов regexp.exec возвращает первое совпадение и запоминает его позицию в свойстве regexp.lastIndex. Последующий поиск он начнёт уже с этой позиции. Если совпадений не найдено, то сбрасывает regexp.lastIndex в ноль.

var str = 'Многое по JavaScript можно найти на сайте http://javascript.ru';

var regexp = /javascript/ig;
var result;

"Начальное значение lastIndex: " + regexp.lastIndex; // 0

while (result = regexp.exec(str)) { // когда нет совпадений, возвращает null
'Найдено: ' + result[0] + ' на позиции:' + result.index ; // 10, 49
'Свойство lastIndex: ' + regexp.lastIndex ; // 20, 59
}

'Конечное значение lastIndex: ' + regexp.lastIndex; // 0 регексп сброшен в ноль

Поиск с нужной позиции

Можно заставить regexp.exec искать сразу с нужной позиции, если поставить lastIndex вручную:

var str = 'Многое по JavaScript можно найти на сайте http://javascript.ru';

var regexp = /javascript/ig;
regexp.lastIndex = 40;

regexp.exec(str).index ; // 49, поиск начат с 40-й позиции

Итого, рецепты

Для поиска только одного совпадения:

  • Найти позицию первого совпадения – str.search(reg).
  • Найти само совпадение – str.match(reg).
  • Проверить, есть ли хоть одно совпадение – regexp.test(str) или str.search(reg) != -1.
  • Найти совпадение с нужной позиции – regexp.exec(str), начальную позицию поиска задать в regexp.lastIndex.

Для поиска всех совпадений:

  • Найти массив совпадений – str.match(reg), с флагом g.
  • Получить все совпадения, с подробной информацией о каждом – regexp.exec(str) с флагом g, в цикле. Для поиска-и-замены: : - Замена на другую строку или результат функции -- str.replace(reg, str|func) Для разбивки строки на части:
  • str.split(str|reg)

Классы и спецсимволы

\d

Цифра, символ от 0 до 9.

\s

Пробельный символ, включая табы, переводы строки и т.п.

\w

Символ «слова», а точнее – буква латинского алфавита или цифра или подчёркивание '_'. Не-английские буквы не являются \w, то есть русская буква не подходит.

\b

Граница слова, обозначает не символ, а границу между символами. Граница имеет «нулевую ширину» в том смысле, что обычно символам регулярного выражения соответствуют символы строки, но не в этом случае.

"Hello, Java!".match(/\bJava\b/) // Java
"Hello, Javascript!".match(/\bJava\b/) // null

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

\D

Не-цифра, то есть любой символ кроме \d, например буква.

\S

Не-пробел, то есть любой символ кроме \s, например буква.

\W

Любой символ, кроме \w, то есть не латинница, не подчёркивание, не цифра. В частности, русские буквы принадлежат этому классу.

\B

Проверка, обратная \b.

Пробелы – обычные символы

В регулярном выражении все символы имеют значение. Даже (и тем более) – пробелы.

Точка – любой символ

В регулярном выражении, точка "." обозначает любой символ, кроме перевода строки:

var re = /CS.4/;

"CSS4".match(re) // найдено "CSS4"
"CS-4".match(re) // найдено "CS-4"
"CS 4".match(re) // найдено "CS 4" (пробел тоже символ)

Экранирование специальных символов

[ \ ^ $ . | ? * + ( )

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

Или, другими словами, перед символом должен быть обратный слэш '\'.

Наборы и диапазоны [...]

Набор [...]

Например, [еао] означает любой символ из этих трёх: 'а', 'е', или 'о'.

Обратим внимание: несмотря на то, что в наборе указано несколько символов, в совпадении должен присутствовать ровно один из них.

// найти [г или т], а затем "оп"
alert( "Гоп-стоп".match(/[гт]оп/gi) ); // "Гоп", "топ"

Диапазоны [x-y]

Например, [a-z] – произвольный символ от a до z, [0-5] – цифра от 0 до 5.

Символьные классы – всего лишь более короткие записи для диапазонов, в частности:

  • \d – то же самое, что [0-9],
  • \w – то же самое, что [a-zA-Z0-9_],
  • \s – то же самое, что [\t\n\v\f\r ] плюс несколько юникодных пробельных символов.

Поиск слов на русском и английском языках

/[\wа-яё]+/gi

Диапазоны «кроме»

Квадратные скобки, начинающиеся со знака каретки: [^…] находят любой символ, кроме указанных.

Например:

  • [^аеуо] – любой символ, кроме 'a', 'e', 'y', 'o'.
  • [^0-9] – любой символ, кроме цифры, то же что \D.
  • [^\s] – любой не-пробельный символ, то же что \S.

Не нужно экранирование

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

  • Точка '.'.
  • Плюс '+'.
  • Круглые скобки '( )'.
  • Дефис '-', если он находится в начале или конце квадратных скобок, то есть не выделяет диапазон.
  • Символ каретки '^', если не находится в начале квадратных скобок.
  • А также открывающая квадратная скобка '['.

…Впрочем, даже если вы решите «на всякий случай» заэкранировать эти символы, поставив перед ними обратный слэш \ – вреда не будет:

Квантификаторы +, *, ? и {n}

Количество {n}

Количество повторений символа можно указать с помощью числа в фигурных скобках: {n} - квантификатор.

У него есть несколько подформ записи:

Точное количество: {5}

Регэксп \d{5} обозначает ровно 5 цифр, в точности как \d\d\d\d\d.

"Мне 12345 лет".match(/\d{5}/) //  "12345"

Количество от-до: {3,5}

Для того, чтобы найти, например, числа размером от трёх до пяти знаков, нужно указать границы в фигурных скобках: \d{3,5}

"Мне не 12, а 1234 года".match(/\d{3,5}/) // "1234"

Последнее значение можно и не указывать. Тогда выражение \d{3,} найдет числа, длиной от трех цифр:

"Мне не 12, а 1234 года".match(/\d{3,}/) // "1234"

Короткие обозначения

+

Означает «один или более», то же что {1,}.

Например, \d+ находит числа – последовательности из 1 или более цифр:

var str = "+7(903)-123-45-67";

str.match(/\d+/g) // 7,903,123,45,67

?

Означает «ноль или один», то же что и {0,1}. По сути, делает символ необязательным.

Например, регэксп ou?r найдёт o, после которого, возможно, следует u, а затем r.:

var str = "Можно писать color или colour (британский вариант)";

str.match(/colou?r/g) // color, colour

*

Означает «ноль или более», то же что {0,}. То есть, символ может повторяться много раз или вообще отсутствовать.

Пример ниже находит цифру, после которой идёт один или более нулей:

"100 10 1".match(/\d0*/g) // 100, 10, 1

Еще примеры

Регэксп «десятичная дробь» (число с точкой внутри): \d+\.\d+

"0 1 12.345 7890".match(/\d+\.\d+/g) // 12.345

Регэксп «открывающий или закрывающий HTML-тег без атрибутов»: /<\/?[a-z][a-z0-9]*>/i

"<h1>Привет!</h1>".match(/<\/?[a-z][a-z0-9]*>/gi) // <h1>, </h1>

Жадные и ленивые квантификаторы

Жадный режим - режим по умлочанию

var reg = /".+"/g;

var str = 'a "witch" and her "broom" is one';

astr.match(reg) // "witch" and her "broom"

Ленивый режим

Его можно включить, если поставить знак вопроса '?' после квантификатора, так что он станет таким: *? или +? или даже ?? для '?'.

Чтобы не возникло путаницы – важно понимать: обычно ? сам является квантификатором (ноль или один). Но если он стоит после другого квантификатора (или даже после себя), то обретает другой смысл – в этом случае он меняет режим его работы на ленивый.

Регэксп /".+?"/g находит отдельно witch и broom:

var reg = /".+?"/g;

var str = 'a "witch" and her "broom" is one';

str.match(reg) // witch, broom

Ленивость распространяется только на тот квантификатор, после которого стоит ?

Прочие квантификаторы остаются жадными.

"123 456".match(/\d+ \d+?/g) // 123 4

Во втором случаем он находит только одно число, потому что Ленивый режим без необходимости лишний раз квантификатор не повторит.

Альтернативный подход

В данном конкретном случае, возможно искать строки в кавычках, оставаясь в жадном режиме, с использованием регулярного выражения "[^"]+":

var reg = /"[^"]+"/g;

var str = 'a "witch" and her "broom" is one';

str.match(reg)  // witch, broom

Эта логика ни в коей мере не заменяет ленивые квантификаторы!

Она просто другая. И то и другое бывает полезно.

Скобочные группы

'Gogogo now!'.match(/(go)+/i) // "Gogogo"

Без скобок, шаблон /go+/ означал бы g, после которого идёт одна или более o, например: goooo. А скобки «группируют» (go) вместе.

Содержимое группы

Скобки нумеруются слева направо.

При поиске методом String#match в результирующем массиве будет сначала всё совпадение, а далее – скобочные группы. Но метод выдаёт скобочные группы только при поиске без флага /.../g.

Для того, чтобы искать и с флагом /.../g и со скобочными группами, используется метод RegExp#exec:

// Метод String#match
var str = '<h1>Привет, мир!</h1>';
var reg = /<(.*?)>/;

str.match(reg) // массив: <h1>, h1

// Метод RegExp#exec

var str = '<h1>Привет, мир!</h1>';
var reg = /<(.*?)>/g;

var match;

while ((match = reg.exec(str)) !== null) {
  // сначала выведет первое совпадение: <h1>,h1
  // затем выведет второе совпадение: </h1>,/h1
  match;
}

Вложенные группы

var str = '<span class="my">';

var reg = /<(([a-z]+)\s*([^>]*))>/;

str.match(reg) // <span class="my">, span class="my", span, class="my"

На нулевом месте – всегда совпадение полностью, далее – группы. Нумерация всегда идёт слева направо, по открывающей скобке.

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

var match = 'ack'.match(/a(z)?(c)?/)

match.length  // 3
match[0] // ac, всё совпадение
match[1] // undefined, для (z)? ничего нет
match[2] // c

Исключение из запоминания через ?:

Скобочную группу можно исключить из запоминаемых и нумеруемых, добавив в её начало ?:.

var str = "Gogo John!";
var reg = /(?:go)+ (\w+)/i;

var result = str.match(reg);

result.length // 2
result[0] // Gogo John
result[1] // John - Gogo был проигнорирован

Обратные ссылки: \n и $n

Скобочные группы можно не только получать в результате, но и использовать как в самом паттерне, так и в строке замены.

Группа в строке замены

Ссылки в строке замены имеют вид $n, где n – это номер скобочной группы.

var name = "Александр Пушкин";

name.replace(/([а-яё]+) ([а-яё]+)/i, "$2, $1");  // Пушкин, Александр

Группа в шаблоне

var str = "He said: \"She's the one!\".";

var reg = /(['"])(.*?)\1/g;

str.match(reg) // "She's the one!"

Теперь работает верно! Движок регулярных выражений, найдя первое скобочное выражение – кавычку (['"]), запоминает его и далее \1 означает «найти то же самое, что в первой скобочной группе».

Обратим внимание на два нюанса:

  • Чтобы использовать скобочную группу в строке замены – нужно использовать ссылку вида $1, а в шаблоне – обратный слэш: \1.
  • Чтобы в принципе иметь возможность обратиться к скобочной группе – не важно откуда, она не должна быть исключена из запоминаемых при помощи ?:. Скобочные группы вида (?:...) не участвуют в нумерации.

Альтернация (или) |

Альтернация обозначается символом вертикальной черты | и позволяет выбирать между вариантами

var reg = /html|php|css|java(script)?/gi

var str = "Сначала появился HTML, затем CSS, потом JavaScript"

str.match(reg) // 'HTML', 'CSS', 'JavaScript'

В отличии от gr[ae]y, который позволяет выбирать посимвольно (найдёт gray, либо grey). Альтернация работает на уровне фраз и подвыражений, например: before(XXX|YYY)after будет искать beforeXXXafter или beforeYYYafter

Начало строки ^ и конец $

Знак каретки ^ и доллара $ имеют в регулярном выражении особый смысл. Их называют «якорями» (anchor – англ.).

Каретка ^ совпадает в начале текста, а доллар $ – в конце.

Якоря являются не символами, а проверками.

Без якорей, regexp найдет все числа

var str = '100500 попугаев съели 500100';
str.match(/\d+/ig) // 100500, 500100 (нашло все числа)

С кареткой ^:

str.match(/^\d+/ig) // 100500 (только в начале строки)

Со знаком доллара $:

str.match(/\d+$/ig) // 500100

Оба якоря используют одновременно, если требуется, чтобы шаблон охватывал текст с начала и до конца.

Например поиск дроби, и ничего другого

var num = "ля-ля 12.34";
num.match(/^\d+\.\d+$/ig) // null, не дробь

var num = "12.34";
num.match(/^\d+\.\d+$/ig) // 12.34, дробь!

Многострочный режим, флаг "m"

В мультистрочном режиме /***/m:

  • Символ ^ означает начало строки.
  • Символ $ означает конец строки.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment