var regexp = new RegExp("шаблон", "флаги");
// or
var regexp = /шаблон/; // без флагов
var regexp = /шаблон/gmi; // с флагами gmi
Слеши "/"
говорят JavaScript о том, что это регулярное выражение. Они играют здесь ту же роль, что и кавычки для обозначения строк.
i
Если этот флаг есть, то регэксп ищет независимо от регистра, то есть не различает между А и а.
g
Если этот флаг есть, то регэксп ищет все совпадения, иначе – только первое.
m
Многострочный режим.
Возвращает позицию первого совпадения или -1, если ничего не найдено.
var str = "Люблю регэкспы я, но странною любовью";
str.search( /лю/i ) // 0
str.search( /но/i ) // 18
str.search( /робот/i ) // 18
Ограничение метода search – он всегда ищет только первое совпадение.
Находит только одно, первое совпадение. Результат вызова – это массив, состоящий из этого совпадения, с дополнительными свойствами index – позиция, на которой оно обнаружено и input – строка, в которой был поиск.
var str = "ОЙ-Ой-ой";
str.match( /ой/i ); // ["ОЙ", index: 0, input: "ОЙ-Ой-ой"]
Если часть шаблона обозначена скобками, то она станет отдельным элементом массива.
var str = "javascript - это такой язык";
str.match( /JAVA(SCRIPT)/i ); // ["javascript", "script", index: 0, input: "javascript - это такой язык"]
Возвращает обычный массив из всех совпадений. Никаких дополнительных свойств у массива в этом случае нет, скобки дополнительных элементов не порождают.
var str = "ОЙ-Ой-ой";
str.match( /ой/ig ); // ["ОЙ", "Ой", "ой"]
str.match( /йо/ig ); // null - нет совпадений
В случае, если совпадений не было, match возвращает null
Обратите внимание, это важно – если match
не нашёл совпадений, он возвращает не пустой массив, а именно null
.
Это важно иметь в виду, чтобы не попасть в такую ловушку:
var str = "Ой-йой-йой";
// результат match не всегда массив!
str.match(/лю/gi).length // ошибка! нет свойства length у null
Разбивает строку в массив по разделителю – регулярному выражению regexp
или подстроке substr.
'12-34-56'.split(/-/) // [12, 34, 56]
Простейшее применение
// заменить дефис на двоеточие
'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;
});
Метод test
проверяет, есть ли хоть одно совпадение в строке str
. Возвращает true/false
.
var str = "Люблю регэкспы я, но странною любовью";
/лю/i.test(str) // true
/помидор/i.test(str) // false
Метод ведёт себя по-разному, в зависимости от того, есть ли у регэкспа флаг 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) ); // "Гоп", "топ"
Например, [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}
- квантификатор.
У него есть несколько подформ записи:
Регэксп \d{5}
обозначает ровно 5 цифр, в точности как \d\d\d\d\d
.
"Мне 12345 лет".match(/\d{5}/) // "12345"
Для того, чтобы найти, например, числа размером от трёх до пяти знаков, нужно указать границы в фигурных скобках: \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
– это номер скобочной группы.
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
:
- Символ
^
означает начало строки. - Символ
$
означает конец строки.