Регулярные выражения — это своего рода язык поиска и осуществления различных манипуляций с текстом, используя различные мета-символы. Регулярные выражения позволяют создавать шаблоны для поиска подстрок, удовлетворяющим заданным условиям. Подобный функционал имеется на вооружении большинства языков программирования, и Javascript — один из таких языков.
Область применения регулярных выражений
В прошлом уроке мы разбирали работу со строками и там было несколько функций для поиска и извлечения искомых подстрок. Может возникнуть вопрос, а зачем придумывать что-то еще, если у нас уже есть достаточно богатый функционал для раздербанивания и анализа строк? Отвечаю, при работе с огромным количество текста, особенно, который генерируется динамически, можно проследить некоторые паттерны(повторяющиеся фрагменты и структура текста в-целом). Допустим, нам нужно выдрать из таблички все названия товаров и цены, а сколько данных будет в таблице — нам не известно. Можно в цикле использовать indexOf()
и substring()
, но код получится громоздким и не очень надежным. Регулярные выражения очень удобно использовать для валидации данных, например для электронной почты, номера телефона, даты и т.д.
Помните задачку из прошлого урока «Определение баланса биткойн-крана»? Там мы находили определенный тэг и из него извлекали текст, после чего получали оттуда цифру. Если мы попытались бы использовать тот же скрипт на другом кране — не факт, что он заработал бы, поскольку сведения о балансе могли находится в совершенно другом тэге с другим классом и другими атрибутами.
При помощи регулярных выражений мы можем сделать универсальный скрипт, который будет искать баланс крана не по тэгу, а в тексте страницы.
Алгоритм такой:
- Мы получаем содержимое всей страницы в текстовом формате
- Составляем паттерн на основе строки Balance: 145335 satoshi. Логически это выглядит примерно так
[Balance:][пробел или другие разделители][последовательность из 1-9 цифр][пробел или другие разделители][ satoshi]
- Ищем в тексте все совпадения с нашим паттерном и при успехе, вытаскиваем значение из 1-9 цифр.
Выглядеть это будет так:
var str = window.document.querySelector('body').textContent; var re = /Balance:\s{0,}(\d{1,9})\s{0,}satoshi/igm; var result = re.exec(str); window.console.log(result); // ["Balance: 145335 satoshi", "145335"] window.console.log(result[1]); // 145335 - это баланс нашего крана
Я пока не буду подробно разбирать этот код, все подробности ниже.Что действительно круто, регулярные выражения работают очень быстро и позволяют просто с хирургической точностью вытаскивать нужные данные и мы можем легко проанализировать все совпадения с заданным паттерном.
Создание простого регулярного выражения и флаги
Для тестирования и написания паттернов в режиме онлайн я обычно использую сервис https://regex101.com. Выбираете там Javascript и смотрите в риалтайме, как обрабатывается текст вашей регуляркой, плюс там есть подсказки и небольшой справочник.
Есть несколько способов задания регулярного выражения. Вот пример синтаксиса:
// Стандартный метод var re = new RegExp("паттерн", "флаги"); // Укороченная форма записи var re = /паттерн/; // без флагов var re = /паттерн/gmi; // с флагами gmi
Флаги — это параметры поиска, их всего несколько видов и вы можете использовать любой из них, или даже все сразу.
i — ignore case, Если этот флаг есть, то регэксп ищет независимо от регистра, то есть не различает между А и а.
g — global match, Если этот флаг есть, то регэксп ищет все совпадения, иначе – только первое.
m — multiline, Многострочный режим.
Пример использования:
var str = 'Писать ботов на iMacros+JS очень круто!'; window.console.log(/imacros/i.test(str)); // true window.console.log(/imacros/.test(str)); // false
Методы Javascript для работы с регулярными выражениями
В Javascript Существует 6 методов для работы с регулярными выражениями. Чаще всего мы будем использовать только половину из них.
Метод exec()
Метод RegExp, который выполняет поиск совпадения в строке. Он возвращает массив данных. Например:
var str = 'Some fruit: Banana - 5 pieces. For 15 monkeys.'; var re = /(\w+) - (\d) pieces/ig; var result = re.exec(str); window.console.log(result); // result = ["Banana - 5 pieces", "Banana", "5"] // Так же мы можем посмотреть позицию совпадения - result.index
В результате мы получим массив, первым элементом которого будет вся совпавшая по паттерну строка, а дальше содержимое скобочных групп. Если совпадений с паттерном нету, то result = null
.
Метод test()
Метод RegExp, который проверяет совпадение в строке, возвращает либо true, либо false. Очень удобен, когда нам необходимо проверить наличие или отсутствие паттерна в тексте. Например:
var str = 'Balance: 145335 satoshi'; var re = /Balance:/ig; var result = re.test(str); window.console.log(result); // true
В данном примере, есть совпадение с паттерном, поэтому получаем true.
Метод search()
Метод String, который тестирует на совпадение в строке. Он возвращет индекс совпадения, или -1 если совпадений не будет найдено. Очень похож на метод indexOf() для работы со строками. Минус этого метода — он ищет только первое совпадение. Для поиска всех совпадений используйте метод match().
var str = "Умея автоматизировать процессы, можно зарабатывать миллионы"; window.console.log(str.search(/можно/igm)); // 60 window.console.log(str.search(/атата/igm)); // -1
Метод match()
Метод String, который выполняет поиск совпадения в строке. Он возвращет массив данных либо null если совпадения отсутствуют.
// Без использования скобочных групп var str = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; var regexp = /[A]/gi; var matches_array = str.match(regexp); window.console.log(matches_array); // ["A", "a"] // С использованием скобочных групп без флага g var str = 'Fruits quantity: Apple - 5, Banana - 7, Orange - 12. I like fruits.'; var found = str.match(/(\d{1,2})/i); window.console.log(found); // Находит первое совпадение и возвращает объект // { // 0: "5" // 1: "5" // index: 25 // input: "Fruits quantity: Apple -...ge - 12. I like fruits." // } // С использованием скобочных групп с флагом g var found = str.match(/(\d{1,2})/igm); window.console.log(found); // ["5", "7", "12"]
Если совпадений нету — возвращает null.
Метод replace()
Метод String, который выполняет поиск совпадения в строке, и заменяет совпавшую подстроку другой подстрокой переданной как аргумент в этот метод. Мы уже использовали эту функцию для работы о строками, регулярные выражения привносят новые возможности.
// Обычная замена var str = 'iMacros is awesome, and iMacros is give me profit!'; var newstr = str.replace(/iMacros/gi, 'Javascript'); window.console.log(newstr); // Javascript is awesome, and Javascript is give me profit! // Замена, используя параметры. Меняем слова местами: var re = /(\w+)\s(\w+)/; var str = 'iMacros JS'; var newstr = str.replace(re, '$2, $1'); // в переменных $1 и $2 находятся значения из скобочных групп window.console.log(newstr); // JS iMacros
У метода replace() есть очень важная особенность — он имеет свой каллбэк. То есть, в качестве аргумента мы можем подавать функцию, которая будет обрабатывать каждое найденное совпадение.
Нестандартное применение метода replace():
var str = ` I have some fruits: Orange - 5 pieces Banana - 7 pieces Apple - 15 pieces It's all. `; var arr = []; // Сюда складируем данные о фруктах и их количестве var newString = str.replace(/(\w+) - (\d) pieces/igm, function (match, p1, p2, offset, string) { window.console.log(arguments); arr.push({ name: p1, quantity: p2 }); return match; }); window.console.log(newString); // Текст не изменился, как и было задумано window.console.log(arr); // Мы получили удобный массив объектов, с которым легко и приятно работать
Как вы видите, мы использовали этот метод для обработки каждого совпадения. Мы вытащили из паттерна название фрукта и количество и поместили эти значения в массив объектов, как мы уже делали ранее. Обратите внимание на аргумент функции offset — это будет индекс начала совпадения, этот параметр нам потом пригодится. В нашем случае, мы имеем 2 скобочные группы в паттерне, поэтому у нас в функции 5 аргументов, но их там может быть и больше.
Метод split()
Метод String, который использует регулярное выражение или фиксированую строку чтобы разбить строку на массив подстрок.
var str = "08-11-2016"; // Разбиваем строку по разделителю window.console.log(str.split('-')); // ["08", "11", "2016"] // Такой же пример с регэкспом window.console.log(str.split(/-/)); // ["08", "11", "2016"]
Составление регулярных выражений
Для поиска символов определенного вида в регулярных выражениях есть «классы символов». Например \d
ищет одну цифру. Есть и другие классы.
Основные классы
\d
– цифры.\D
– не-цифры.\s
– пробельные символы, переводы строки.\S
– всё, кроме \s.\w
– латиница, цифры, подчёркивание ‘_’.\W
– всё, кроме \w.\t
– символ табуляции\n
– символ перевода строки.
– точка обозначает любой символ, кроме перевода строки.
Помимо классов, есть наборы символов, причем помимо стандартных, можно самому создавать набор символов, используя []
.
Наборы символов
[a-z]
– произвольный символ от a до z[B-G] –
произвольный символ от B до G в верхнем регистре[0-9]
– то же самое, что и \d, любая цифра от 0 до 9[a-zA-Z0-9]
– любая цифра или буква, можно комбинировать диапазоны[^0-9]
– диапазон «кроме», ищет любые символы, кроме цифр
Обратите внимание, в квадратных скобках, большинство специальных символов можно использовать без экранирования.
Экранируем символы
[ \ ^ $ . | ? * + ( )
Не экранируем в квадратных скобках
- Точка
'.'
. - Плюс
'+'
. - Круглые скобки
'( )'
. - Дефис
'-'
, если он находится в начале или конце квадратных скобок, то есть не выделяет диапазон. - Символ каретки
'^'
, если не находится в начале квадратных скобок. - А также открывающая квадратная скобка
'['
.
Квантификаторы +, *, ? и {n}
- Количество {n}
\d{5}
— 5 цифр
\d{1,}
— одна или больше цифр
\d{1,5}
— от одной до 5 цифр - Один или более +, аналог {1,}
\d+
— одна или более цифр
[a-z]+
— одна или более букв от a до z - Ноль или один ?, аналог {0,1}
\colo?r\
— найдет color и colour - Означает «ноль или более» *, аналог {0,}
\d0*
— найдет «1» и «100» в строке «1 100», символ может повторяться много раз или вообще отсутствовать.
Скобочные группы
Вы можете заключить одну или несколько частей шаблона в скобки — это и будет называться скобочной группой. Основной профит — при использовании методов match, exec, replace — можно вытащить значения в скобках в отдельный элемент массива. И еще, если поставить квантификатор после скобки, то он применится ко всей скобке, а не к одному символу. Еще вы можете использовать вложенные скобки, то есть разбивать большой шаблон на несколько маленьких.
Пример использования вы можете посмотреть выше — в нестандартном применении метода replace().
Альтернация
Простым языком, это «ИЛИ».
/0|1|2|3|4|5|6|7|8|9/
— аналог \d -любая цифра
/imacros|js/
— найдет «imacros» или «js»
Начало строки ^ и конец $
Знак каретки ‘^’ и доллара ‘$’ имеют в регулярном выражении особый смысл. Их называют «якорями» (anchor – англ.).
Каретка ^
совпадает в начале текста, а доллар $
– в конце. Знак доллара $ используют, чтобы указать, что паттерн должен заканчиваться в конце текста, знак каретки ^ — что паттерн должен начинаться с первого символа строки.
Подытожим
Это базовые данные о регулярных выражениях, можете использовать эту статью, как небольшую шпаргалку. В следующей главе мы рассмотрим, каким образом нужно составлять регулярные выражения и обещаю много практических примеров, которые вам обязательно пригодятся при написании макросов.
Оставляйте ваши пожелания, вопросы и комментарии!
Доброго времени! Ну очень хорошо разжевываете! Ставлю на 1е место по простоте изложения.
У меня задачка — спарсить последний № телефона со страницы, он записан в виде +79851234567 — тут плюсик и 11 цифр
window.console.log(window.document.querySelectorAll(«‘+’\d{11}») );
не получается. Подскажите, как должно выглядеть выражение.
Александр, регулярное выражение вы правильное составили, но метод window.document.querySelectorAll() принимает в качестве аргумента CSS-селектор(регулярки не поддерживает).
Навскидку вижу два варианта:
1) Вы получаете текст всей страницы и регулярками ищете номер телефона.
var str = window.document.querySelector('body').textContent;
var result = /\d{1,11}/igm.exec(str);
window.console.log(result[1]);
2) При помощи
window.document.querySelector()
ищете тэг, в котором содержится номер телефона и оттуда уже регулярками вытаскиваете цифры.Использовал 1-й вариант, поскольку вытаскивать тлф.нужно было из таблицы, сделал так.
var str = window.document.querySelector(‘tbody’).textContent;
var result = /[+]\d{1,11}/igm.exec(str);
Из полного body как ни бился, не получилось.
Только с добавлением плюсика выбирался только ненужный 1й телефон.
Александр, используйте «Нестандартное применение метода replace():» из статьи. Так вы сможете выдрать все телефоны на странице и выбрать нужный, например по индексу. Но я рекомендую использовать второй способ, он более надежный и точный.
Спасибо, меня устраивает щас в виде
var koshel = /\d{11}QIWI/igm.exec(str); //79131234567QIWI
Киви
+79131238628
QIWI
Верифицирован
Это инспектирование элемента при помощи Firebug
Здравствуйте!!!!!!
не подскажите
if(переменная1.indexOf(«переменная2») + 1)
почему у меня не работает с переменная2?
а если просто слово пишешь «забор» то все работает?
Алексей, во-первых приводите реальный код или вы действительно используете переменные на кириллице?
Во-вторых, я вижу отсутствие кавычек у первой переменной и наличие у второй, если это кусок реального кода, то уберите кавычки для второй переменной.
В-третьих, вы используете сокращенный вариант условия if, который подразумевает, что если условие или переменная будет true — то код после фигурных скобок выполнится.
Я вижу, вы используете прибавление «+1» для подгонки результата, но это не верно, метод indexOf() работает немного иначе:
Ну и разумеется, вместо значений в кавычках, вы можете использовать обычные переменные, я оперировал значениями для наглядности.
спасибо большое за разъяснения!!!
«затупил» с кавычками
****************************************************
var zap1 =(‘кошка. собака’)
var zap = zap1.replace(‘собака’,»); // удалит содержимое кавычек (‘собака’) в переменной
****************************************************
а можно удалять не конкретный текст а все что после «.»
Подскажите пожалуйста в чем может быть проблемма??
var paRS =(‘Мартынова’)
var paRSS =(‘Мартынова’)
if(paRS.indexOf(paRSS) ){c(60,’WAIT SECONDS=1′);}
else {c(60,’WAIT SECONDS=2′);}
выдаёт 2 сек
почему????
проблема именно с этим словом!!
что можно сделать??
спасибо еще чють подумал и разобрался
Алексейка, молодцом! Чуть выше в комментарии разжевано, как работает indexOf. Буду еще вопросы — пишите!
не могу придумать регулрное выражение
[CODE]
//—— из строковой переменной возвращает значение атрибута
function getAttr(vStr,vAttr) {
//
var re = /(vAttr + ‘=\»‘ «)/igm; //не знаю как задать выражение
var result = re.exec(vStr);
return result;
};
//——- end function ————
var vUrl = ‘✰ DeViL^NeKo ✰ | Аниме Ecchi | hentai‘;
window.console.log(getAttr(vUrl,’href’));
//хочу вернуть — «/devil_neko_new3»
[/CODE]
пс. А какими тегами вы код обрамлете.
выкрутился без регулырных..
//====== функция =========
// из строковой переменной возвращает значение атрибута
// типа так
// vUrl = ‘? DeViL^NeKo ? | Аниме Ecchi | hentai‘;
// window.console.log(getAttr(vUrl,’href’);
// ———
function getAttr(vStr,vAttr) {
//
var result = «»;
var start = vStr.indexOf(vAttr) + 2 + vAttr.length; //
//
for (var n = start; n < vStr.length; n++) {
if (vStr.charAt(n) == '"') {
break; // если дошли до " то закончить
};
result += vStr.charAt(n);
};
return result;
};
//======== end function =========