Javascript для начинающих: изучаем регулярные выражения
Содержание:
- Методы Javascript для работы с регулярными выражениями
- Операторы контроля
- Жадность
- Строковые методы, поиск и замена
- Поиск совпадений: метод exec
- Полезные методы работы с регулярными выражениями в JavaScript
- Точка – это любой символ
- Жадность
- Захват групп
- Указание количества повторений символов в тексте
- search()
- Metacharacters
- Содержимое скобок в match
- Проверка наличия совпадения
- Quantifiers
- matchAll()
- Как создавать простые шаблоны?
- Как создавать сложные шаблоны со специальными символами?
Методы 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 = // Так же мы можем посмотреть позицию совпадения - result.index
В результате мы получим массив, первым элементом которого будет вся совпавшая по паттерну строка, а дальше содержимое скобочных групп. Если совпадений с паттерном нету, то .
Метод 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 = //gi; var matches_array = str.match(regexp); window.console.log(matches_array); // // С использованием скобочных групп без флага 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); //
Если совпадений нету — возвращает 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('-')); // // Такой же пример с регэкспом window.console.log(str.split(/-/)); //
Операторы контроля
Ещё один вид специальных символов — это операторы контроля. Такие символы позволяют описывать шаблоны с границами, то есть указывать, где начинается или заканчивается слово или строка. С помощью операторов контроля также можно создавать более сложные шаблоны, такие как опережающие проверки, ретроспективные проверки и условные выражения.
/* Оператор контроля - Значение */^ - начало строки (последующее регулярное выражение должно совпадать с началом проверяемой строки).$ - конец строки (последующее регулярное выражение должно совпадать с концом проверяемой строки).\b - граница слова, то есть его начало или конец.\B - несловообразующая граница.x(?=y) - опережающая проверка. Совпадение с "x", только если за "x" следует "y".x(?!y) - негативная опережающая проверка. Совпадение с "x", только если за "x" не следует "y".(?<=y)x - ретроспективная проверка. Совпадение с "x", только если перед "x" стоит "y".(?<!y)x - негативная ретроспективная проверка. Совпадение с "x", только если перед "x" не стоит "y".
Примеры:
// ^ - Начало строкиconst myPattern = /^re/console.log(myPattern.test('write'))// falseconsole.log(myPattern.test('read'))// trueconsole.log(myPattern.test('real'))// trueconsole.log(myPattern.test('free'))// false// $ - Конец строкиconst myPattern = /ne$/console.log(myPattern.test('all is done'))// trueconsole.log(myPattern.test('on the phone'))// trueconsole.log(myPattern.test('in Rome'))// falseconsole.log(myPattern.test('Buy toner'))// false// \b - Граница словаconst myPattern = /\bro/console.log(myPattern.test('road'))// trueconsole.log(myPattern.test('steep'))// falseconsole.log(myPattern.test('umbro'))// false// Илиconst myPattern = /\btea\b/console.log(myPattern.test('tea'))// trueconsole.log(myPattern.test('steap'))// falseconsole.log(myPattern.test('tear'))// false// \B - Несловообразующая границаconst myPattern = /\Btea\B/console.log(myPattern.test('tea'))// falseconsole.log(myPattern.test('steap'))// trueconsole.log(myPattern.test('tear'))// false// x(?=y) - Опережающая проверкаconst myPattern = /doo(?=dle)/console.log(myPattern.test('poodle'))// falseconsole.log(myPattern.test('doodle'))// trueconsole.log(myPattern.test('moodle'))// false// x(?!y) - Негативная опережающая проверкаconst myPattern = /gl(?!u)/console.log(myPattern.test('glue'))// falseconsole.log(myPattern.test('gleam'))// true// (?<=y)x - Ретроспективная проверкаconst myPattern = /(?<=re)a/console.log(myPattern.test('realm'))// trueconsole.log(myPattern.test('read'))// trueconsole.log(myPattern.test('rest'))// false// (?<!y)x - Негативная ретроспективная проверкаconst myPattern = /(?<!re)a/console.log(myPattern.test('break'))// falseconsole.log(myPattern.test('treat'))// falseconsole.log(myPattern.test('take'))// true
Жадность
Это не совсем особенность, скорее фича, но все же достойная отдельного абзаца.
Все регулярные выражения в javascript – жадные. То есть, выражение старается отхватить как можно больший кусок строки.
Например, мы хотим заменить все открывающие тэги
На что и почему – не так важно
При запуске вы увидите, что заменяется не открывающий тэг, а вся ссылка, выражение матчит её от начала и до конца.
Это происходит из-за того, что точка-звёздочка в «жадном» режиме пытается захватить как можно больше, в нашем случае – это как раз до последнего .
Последний символ точка-звёздочка не захватывает, т.к. иначе не будет совпадения.
Как вариант решения используют квадратные скобки: :
Это работает. Но самым удобным вариантом является переключение точки-звёздочки в нежадный режим. Это осуществляется простым добавлением знака «» после звёздочки.
В нежадном режиме точка-звёздочка пустит поиск дальше сразу, как только нашла совпадение:
В некоторых языках программирования можно переключить жадность на уровне всего регулярного выражения, флагом.
В javascript это сделать нельзя… Вот такая особенность. А вопросительный знак после звёздочки рулит – честное слово.
Строковые методы, поиск и замена
Следующие методы работают с регулярными выражениями из строк.
Все методы, кроме replace, можно вызывать как с объектами типа regexp в аргументах, так и со строками, которые автоматом преобразуются в объекты RegExp.
Так что вызовы эквивалентны:
var i = str.search(/\s/) var i = str.search("\\s")
При использовании кавычек нужно дублировать \ и нет возможности указать флаги. Если регулярное выражение уже задано строкой, то бывает удобна и полная форма
var regText = "\\s" var i = str.search(new RegExp(regText, "g"))
Возвращает индекс регулярного выражения в строке, или -1.
Если Вы хотите знать, подходит ли строка под регулярное выражение, используйте метод (аналогично RegExp-методы ). Чтобы получить больше информации, используйте более медленный метод (аналогичный методу ).
Этот пример выводит сообщение, в зависимости от того, подходит ли строка под регулярное выражение.
function testinput(re, str){ if (str.search(re) != -1) midstring = " contains "; else midstring = " does not contain "; document.write (str + midstring + re.source); }
Если в regexp нет флага , то возвращает тот же результат, что .
Если в regexp есть флаг , то возвращает массив со всеми совпадениями.
Чтобы просто узнать, подходит ли строка под регулярное выражение , используйте .
Если Вы хотите получить первый результат — попробуйте r.
В следующем примере используется, чтобы найти «Chapter», за которой следует 1 или более цифр, а затем цифры, разделенные точкой. В регулярном выражении есть флаг , так что регистр будет игнорироваться.
str = "For more information, see Chapter 3.4.5.1"; re = /chapter (\d+(\.\d)*)/i; found = str.match(re); alert(found);
Скрипт выдаст массив из совпадений:
- Chapter 3.4.5.1 — полностью совпавшая строка
- 3.4.5.1 — первая скобка
- .1 — внутренняя скобка
Следующий пример демонстрирует использование флагов глобального и регистронезависимого поиска с . Будут найдены все буквы от А до Е и от а до е, каждая — в отдельном элементе массива.
var str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; var regexp = //gi; var matches = str.match(regexp); document.write(matches); // matches =
Метод replace может заменять вхождения регулярного выражения не только на строку, но и на результат выполнения функции. Его полный синтаксис — такой:
var newString = str.replace(regexp/substr, newSubStr/function)
- Объект RegExp. Его вхождения будут заменены на значение, которое вернет параметр номер 2
- Строка, которая будет заменена на .
- Строка, которая заменяет подстроку из аргумента номер 1.
- Функция, которая может быть вызвана для генерации новой подстроки (чтобы подставить ее вместо подстроки, полученной из аргумента 1).
Метод не меняет строку, на которой вызван, а просто возвращает новую, измененную строку.
Чтобы осуществить глобальную замену, включите в регулярное выражение флаг .
Если первый аргумент — строка, то она не преобразуется в регулярное выражение, так что, например,
var ab = "a b".replace("\\s","..") // = "a b"
Вызов replace оставил строку без изменения, т.к искал не регулярное выражение , а строку «\s».
В строке замены могут быть такие спецсимволы:
Pattern | Inserts |
Вставляет «$». | |
Вставляет найденную подстроку. | |
Вставляет часть строки, которая предшествует найденному вхождению. | |
Вставляет часть строки, которая идет после найденного вхождения. | |
or | Где или — десятичные цифры, вставляет подстроку вхождения, запомненную -й вложенной скобкой, если первый аргумент — объект RegExp. |
Если Вы указываете вторым параметром функцию, то она выполняется при каждом совпадении.
В функции можно динамически генерировать и возвращать строку подстановки.
Первый параметр функции — найденная подстрока. Если первым аргументом является объект , то следующие параметров содержат совпадения из вложенных скобок. Последние два параметра — позиция в строке, на которой произошло совпадение и сама строка.
Например, следующий вызов возвратит XXzzzz — XX , zzzz.
function replacer(str, p1, p2, offset, s) { return str + " - " + p1 + " , " + p2; } var newString = "XXzzzz".replace(/(X*)(z*)/, replacer)
Как видите, тут две скобки в регулярном выражении, и потому в функции два параметра , .
Если бы были три скобки, то в функцию пришлось бы добавить параметр .
Следующая функция заменяет слова типа на :
function styleHyphenFormat(propertyName) { function upperToHyphenLower(match) { return '-' + match.toLowerCase(); } return propertyName.replace(//, upperToHyphenLower); }
Поиск совпадений: метод exec
Метод возвращает массив и ставит свойства регулярного выражения.
Если совпадений нет, то возвращается null.
Например,
// Найти одну d, за которой следует 1 или более b, за которыми одна d // Запомнить найденные b и следующую за ними d // Регистронезависимый поиск var myRe = /d(b+)(d)/ig; var myArray = myRe.exec("cdbBdbsbz");
В результате выполнения скрипта будут такие результаты:
Объект | Свойство/Индекс | Описания | Пример |
Содержимое . | |||
Индекс совпадения (от 0) | |||
Исходная строка. | |||
Последние совпавшие символы | |||
Совпадения во вложенных скобках, если есть. Число вложенных скобок не ограничено. | |||
Индекс, с которого начинать следующий поиск. | |||
Показывает, что был включен регистронезависимый поиск, флаг «». | |||
Показывает, что был включен флаг «» поиска совпадений. | |||
Показывает, был ли включен флаг многострочного поиска «». | |||
Текст паттерна. |
Если в регулярном выражении включен флаг «», Вы можете вызывать метод много раз для поиска последовательных совпадений в той же строке. Когда Вы это делаете, поиск начинается на подстроке , с индекса . Например, вот такой скрипт:
var myRe = /ab*/g; var str = "abbcdefabh"; while ((myArray = myRe.exec(str)) != null) { var msg = "Found " + myArray + ". "; msg += "Next match starts at " + myRe.lastIndex; print(msg); }
Этот скрипт выведет следующий текст:
Found abb. Next match starts at 3 Found ab. Next match starts at 9
В следующем примере функция выполняет поиск по input. Затем делается цикл по массиву, чтобы посмотреть, есть ли другие имена.
Предполагается, что все зарегистрированные имена находятся в массиве А:
var A = ; function lookup(input) { var firstName = /\w+/i.exec(input); if (!firstName) { print(input + " isn't a name!"); return; } var count = 0; for (var i = 0; i < A.length; i++) { if (firstName.toLowerCase() == A.toLowerCase()) count++; } var midstring = (count == 1) ? " other has " : " others have "; print("Thanks, " + count + midstring + "the same name!") }
Полезные методы работы с регулярными выражениями в JavaScript
Регулярные выражения, создаваемые с использованием флагов и последовательностей символов, которые мы обсуждали ранее в этой статье, предназначены для использования с различными методами JavaScript для поиска, замены или разделения строк.
Вот некоторые методы, связанные с регулярными выражениями.
► test() – проверяет, содержит ли основная строка подстроку, которая соответствует шаблону, заданному данным регулярным выражением. При успешном совпадении метод возвращает true, в противном случае — false.
JavaScript
var textA = 'I like APPles very much'; var textB = 'I like APPles'; var regexOne = /apples$/i // вернет false console.log(regexOne.test(textA)); // вернет true console.log(regexOne.test(textB));
В приведённом выше примере приведено регулярное выражение, предназначенное для поиска слова “apples” в случае, если оно расположено в конце строки. Поэтому в первом случае метод вернет false.
► search() – проверяет, содержит ли основная строка подстроку, которая соответствует шаблону, заданному данным регулярным выражением. Метод возвращает индекс совпадения при успехе и -1 в противном случае.
JavaScript
var textA = 'I like APPles very much'; var regexOne = /apples/; var regexTwo = /apples/i; // Результат: -1 console.log(textA.search(regexOne)); // Результат: 7 console.log(textA.search(regexTwo));
В данном примере проверка по превому регулярному выражению вернет -1, потому что не указан флаг нечувствительности к регистру.
► match() – осуществляет поиск подстроки в основной строке. Подстрока должна соответствовать шаблону, заданному данным регулярным выражением. Если используется флаг g, то несколько совпадений будут возвращены в виде массива.
JavaScript
var textA = 'All I see here are apples, APPles and apPleS'; var regexOne = /apples/gi; // Результат: console.log(textA.match(regexOne));
► exec() – производит поиск подстроки в основной строке. В случае, если подстрока соответствует шаблону, заданному данным регулярным выражением, возвращает массив с результатами или null. В свойстве input хранится оригинальная строка
JavaScript
var textA = 'Do you like apples?'; var regexOne = /apples/; // Результат: apples console.log(regexOne.exec(textA)); // Результат : Do you like apples? console.log(regexOne.exec(textA).input);
► replace() – ищет подстроку, соответствующую заданному шаблону и заменяет ее на предоставленную заменяющую строку.
JavaScript
var textA = 'Do you like aPPles?'; var regexOne = /apples/i // Результат: Do you like mangoes? console.log(textA.replace(regexOne, 'mangoes'));
► split() – Этот метод позволит вам разбить основную строку на подстроки на основе разделителя, представленного в виде регулярного выражения.
JavaScript
var textA = 'This 593 string will be brok294en at places where d1gits are.'; var regexOne = /\d+/g // Результат : console.log(textA.split(regexOne))
Точка – это любой символ
Точка – это специальный символьный класс, который соответствует «любому символу, кроме новой строки».
Для примера:
Или в середине регулярного выражения:
Обратите внимание, что точка означает «любой символ», но не «отсутствие символа». Там должен быть какой-либо символ, чтобы соответствовать условию поиска:. Обычно точка не соответствует символу новой строки
Обычно точка не соответствует символу новой строки .
То есть, регулярное выражение будет искать символ и затем , с любым символом между ними, кроме перевода строки :
Но во многих ситуациях точкой мы хотим обозначить действительно «любой символ», включая перевод строки.
Как раз для этого нужен флаг . Если регулярное выражение имеет его, то точка соответствует буквально любому символу:
Внимание, пробелы!
Обычно мы уделяем мало внимания пробелам. Для нас строки и практически идентичны.
Но если регулярное выражение не учитывает пробелы, оно может не сработать.
Давайте попробуем найти цифры, разделённые дефисом:
Исправим это, добавив пробелы в регулярное выражение :
Пробел – это символ. Такой же важный, как любой другой.
Нельзя просто добавить или удалить пробелы из регулярного выражения, и ожидать, что оно будет также работать.
Другими словами, в регулярном выражении все символы имеют значение, даже пробелы.
Жадность
Это не совсем особенность, скорее фича, но все же достойная отдельного абзаца.
Все регулярные выражения в javascript — жадные. То есть, выражение старается отхватить как можно больший кусок строки.
Например, мы хотим заменить все открывающие тэги
На что и почему — не так важно
text = '1 <A href="#">...</A> 2' text = text.replace(/<A(.*)>/, 'TEST') alert(text)
При запуске вы увидите, что заменяется не открывающий тэг, а вся ссылка, выражение матчит ее от начала и до конца.
Это происходит из-за того, что точка-звездочка в «жадном» режиме пытается захватить как можно больше, в нашем случае — это как раз до последнего .
Последний символ точка-звездочка не захватывает, т.к. иначе не будет совпадения.
Как вариант решения используют квадратные скобки: :
text = '1 <A href="#">...</A> 2' text = text.replace(/<A(*)>/, 'TEST') alert(text)
Это работает. Но самым удобным вариантом является переключение точки-звездочки в нежадный режим. Это осуществляется простым добавлением знака «» после звездочки.
В нежадном режиме точка-звездочка пустит поиск дальше сразу, как только нашла совпадение:
text = '1 <A href="#">...</A> 2' text = text.replace(/<A(.*?)>/, 'TEST') alert(text)
В некоторых языках программирования можно переключить жадность на уровне всего регулярного выражения, флагом.
В javascript это сделать нельзя.. Вот такая особенность. А вопросительный знак после звездочки рулит — честное слово.
Захват групп
До сих пор мы видели, как тестировать строки и проверять, содержат ли они определенный шаблон.
Крутая возможность регулярных выражений заключается в том, что можно захватывать определённые части строки и складывать их в массив.
Вы можете делать это с помощью групп, а точнее с помощью захвата групп.
По умолчанию, группы итак захватываются. Теперь вместо использования , который просто возвращает логическое значение, мы будем использовать один из следующих методов:
Они абсолютно одинаковые и оба возвращают массив с проверяемой строкой в качестве первого элемента, а в остальных элементах совпадения для каждой найденной группы.
Если совпадений не найдено, то он возвращает .
Когда группа совпадает несколько раз, то только последнее найденное значение будет добавлено в возвращаемый массив.
Опциональные группы
Захват групп можно сделать опциональным с помощью . Если ничего не будет найдено, то в возвращаемый массив будет добавлен элемент :
Ссылка на найденную группу
Каждой найденной группе присваивается число. ссылается на первый элемент, на второй, и так далее. Это полезно, когда мы будет говорить о замене части строки.
Указание количества повторений символов в тексте
Все приведенные выше регулярные выражения будут совпадать только с одним символом. Чтобы указать, сколько символов должно быть тексте, чтобы произошло совпадение вы можете использовать квантификаторы.
+ – Обозначает одно или более совпадение. Например, чтобы регулярное выражение совпало с набором символов “ABD12D” нужно использовать \w+.
* – Обозначает ноль или более символов. Например, под выражение b\w* подойдут следующие сочетания символов: “b”, “bat”, “bajhdsfbfjhbe”. В данном случае мы ищем соответствие нулевому или более количеству символов в словах после буквы “b”.
{m, n} – Соответствует не менее m и не более n вхождений предыдущего символа. {m,} будет соответствовать не менее, чем m вхождений, верхнего предела в этом случае нет. {k} будет соответствовать точному количеству (k) вхождений предыдущего символа.
? – Обозначает ноль или один символ. Например, это может быть полезно при сопоставлении двух вариантов написания для одной и той же слова. Выражению будут соответствовать оба слова: “behavior” и “behaviour”.
| – Соответствует выражению до или после символа |. Например, выражению /se(a|e)/ — соответсвуют оба слова: “see” и “sea”.
search()
Первый метод, , ищет в строке заданный шаблон. Если он находит совпадение, то возвращает позицию в строке, где это совпадение начинается. Если совпадения нет, возвращается . Нужно запомнить, что метод возвращает позицию только первого совпадения. После нахождения первого совпадения он прекращает работу.
// Синтаксис метода search()// 'проверяемый текст'.search(/шаблон/)// Создание текста для проверкиconst myString = 'The world of code is not full of code.'// Описание шаблонаconst myPattern = /code/// Использование search() для поиска//совпадения строки с шаблоном,//когда search() находит совпадениеmyString.search(myPattern)// -13// Вызов search() прямо на строке,// когда search() не находит совпадений'Another day in the life.'.search(myPattern)// -1
Metacharacters
Metacharacters are characters with a special meaning:
Metacharacter | Description |
---|---|
. | Find a single character, except newline or line terminator |
\w | Find a word character |
\W | Find a non-word character |
\d | Find a digit |
\D | Find a non-digit character |
\s | Find a whitespace character |
\S | Find a non-whitespace character |
\b | Find a match at the beginning/end of a word, beginning like this: \bHI, end like this: HI\b |
\B | Find a match, but not at the beginning/end of a word |
\0 | Find a NULL character |
\n | Find a new line character |
\f | Find a form feed character |
\r | Find a carriage return character |
\t | Find a tab character |
\v | Find a vertical tab character |
\xxx | Find the character specified by an octal number xxx |
\xdd | Find the character specified by a hexadecimal number dd |
\udddd | Find the Unicode character specified by a hexadecimal number dddd |
Содержимое скобок в match
Скобочные группы нумеруются слева направо. Поисковый движок запоминает содержимое, которое соответствует каждой скобочной группе, и позволяет получить его в результате.
Метод , если у регулярного выражения нет флага , ищет первое совпадение и возвращает его в виде массива:
- На позиции будет всё совпадение целиком.
- На позиции – содержимое первой скобочной группы.
- На позиции – содержимое второй скобочной группы.
- …и так далее…
Например, мы хотим найти HTML теги и обработать их. Было бы удобно иметь содержимое тега (то, что внутри уголков) в отдельной переменной.
Давайте заключим внутреннее содержимое в круглые скобки: .
Теперь получим как тег целиком , так и его содержимое в виде массива:
Скобки могут быть и вложенными.
Например, при поиске тега в нас может интересовать:
- Содержимое тега целиком: .
- Название тега: .
- Атрибуты тега: .
Заключим их в скобки в шаблоне: .
Вот их номера (слева направо, по открывающей скобке):
В действии:
По нулевому индексу в всегда идёт полное совпадение.
Затем следуют группы, нумеруемые слева направо, по открывающим скобкам. Группа, открывающая скобка которой идёт первой, получает первый индекс в результате – . Там находится всё содержимое тега.
Затем в идёт группа, образованная второй открывающей скобкой – имя тега, далее в будет остальное содержимое тега: .
Соответствие для каждой группы в строке:
Даже если скобочная группа необязательна (например, стоит квантификатор ), соответствующий элемент массива существует и равен .
Например, рассмотрим регулярное выражение . Оно ищет букву , за которой идёт необязательная буква , за которой, в свою очередь, идёт необязательная буква .
Если применить его к строке из одной буквы , то результат будет такой:
Массив имеет длину , но все скобочные группы пустые.
А теперь более сложная ситуация для строки :
Длина массива всегда равна . Для группы ничего нет, поэтому результат: .
Проверка наличия совпадения
Регулярные выражения используются для описания текста, который требуется найти в строке (и возможно, подвергнуть дополнительной обработке). Давайте вернемся к примеру, который приводился ранее в этом блоге:
DECLARE names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Aaron,Jeff';
Допустим, мы хотим определить на программном уровне, содержит ли строка список имен, разделенных запятыми. Для этого мы воспользуемся функцией , обнаруживающей совпадения шаблона в строке:
DECLARE names VARCHAR2(60) := 'Anna,Matt,Joe,Nathan,Andrew,Jeff,Aaron'; names_adjusted VARCHAR2(61); comma_delimited BOOLEAN; BEGIN --Поиск по шаблону comma_delimited := REGEXP_LIKE(names,'^(*,)+(*){1}$'); --Вывод результата DBMS_OUTPUT.PUT_LINE( CASE comma_delimited WHEN true THEN 'Обнаружен список с разделителями!' ELSE 'Совпадение отсутствует.' END); END;
Результат:
Обнаружен список с разделителями
Чтобы разобраться в происходящем, необходимо начать с выражения, описывающего искомый текст. Общий синтаксис функции выглядит так:
REGEXP_LIKE (исходная_строка, шаблон )
Здесь — символьная строка, в которой ищутся совпадения; шаблон — регулярное выражение, совпадения которого ищутся в исходной_строке; модификаторы — один или несколько модификаторов, управляющих процессом поиска. Если функция находит совпадение шаблона в , она возвращает логическое значение ; в противном случае возвращается .
Процесс построения регулярного выражения выглядел примерно так:
- Каждый элемент списка имен может состоять только из букв и пробелов. Квадратные скобки определяют набор символов, которые могут входить в совпадение. Диапазон a–z описывает все буквы нижнего регистра, а диапазон A–Z — все буквы верхнего регистра. Пробел находится между двумя компонентами выражения. Таким образом, этот шаблон описывает один любой символ нижнего или верхнего регистра или пробел.
- * Звездочка является квантификатором — служебным символом, который указывает, что каждый элемент списка содержит ноль или более повторений совпадения, описанного шаблоном в квадратных скобках.
- *, Каждый элемент списка должен завершаться запятой. Последний элемент является исключением, но пока мы не будем обращать внимания на эту подробность.
- *,) Круглые скобки определяют подвыражение, которое описывает некоторое количество символов, завершаемых запятой. Мы определяем это подвыражение, потому что оно должно повторяться при поиске.
- ]*,)+ Знак + — еще один квантификатор, применяемый к предшествующему элементу (то есть к подвыражению в круглых скобках). В отличие от * знак + означает «одно или более повторений». Список, разделенный запятыми, состоит из одного или нескольких повторений подвыражения.
- ( В шаблон добавляется еще одно подвыражение: (*). Оно почти совпадает с первым, но не содержит запятой. Последний элемент списка не завершается запятой.
- Мы добавляем квантификатор {1}, чтобы разрешить вхождение ровно одного элемента списка без завершающей запятой.
- ^ Наконец, метасимволы ^ и привязывают потенциальное совпадение к началу и концу целевой строки. Это означает, что совпадением шаблона может быть только вся строка вместо некоторого подмножества ее символов.
Функция анализирует список имен и проверяет, соответствует ли он шаблону. Эта функция оптимизирована для простого обнаружения совпадения шаблона в строке, но другие функции способны на большее!
Quantifiers
Quantifier | Description |
---|---|
n+ | Matches any string that contains at least one n |
n* | Matches any string that contains zero or more occurrences of n |
n? | Matches any string that contains zero or one occurrences of n |
n{X} | Matches any string that contains a sequence of X n‘s |
n{X,Y} | Matches any string that contains a sequence of X to Y n‘s |
n{X,} | Matches any string that contains a sequence of at least X n‘s |
n$ | Matches any string with n at the end of it |
^n | Matches any string with n at the beginning of it |
?=n | Matches any string that is followed by a specific string n |
?!n | Matches any string that is not followed by a specific string n |
matchAll()
Подобно методу , возвращает все совпадения при использовании флага в шаблоне. Однако работает он по-другому. Метод возвращает объект . Есть несколько способов извлечь из него все совпадения.
Во-первых, можно пройтись по объекту циклом и вернуть или записать все совпадения. Также можно использовать , чтобы создать массив из содержимого объекта, или оператор spread, который даст точно такой же результат, как и .
// Синтаксис метода match()// ‘проверяемый текст’.match(/шаблон/)// Создание текста для проверкиconst myString = ‘The world of code is not full of code.’// Описание шаблонаconst myPattern = /code/g// Обратите внимание, что используется флаг ‘g’// Использование matchAll() для поиска совпадений в текстеconst matches = myString.matchAll(myPattern)// Использование цикла for…of для получения всех совпаденийfor (const match of matches) { console.log(match)}// [// [// ‘code’,// index: 13,// input: ‘The world of code is not full of code.’,// groups: undefined// ],// [// ‘code’,// index: 33,// input: ‘The world of code is not full of code.’,// groups: undefined// ]// ]// Использование Array.from() для получения всех совпаденийconst matches = Array.from(myString.matchAll(myPattern))// [// [// ‘code’,// index: 13,// input: ‘The world of code is not full of code.’,// groups: undefined// ],// [// ‘code’,// index: 33,// input: ‘The world of code is not full of code.’,// groups: undefined// ]// ]// Использование оператора spread для получения всех совпаденийconst matches = // [// [// ‘code’,// index: 13,// input: ‘The world of code is not full of code.’,// groups: undefined// ],// [// ‘code’,// index: 33,// input: ‘The world of code is not full of code.’,// groups: undefined// ]// ]
Как создавать простые шаблоны?
Вы узнали, как создавать и использовать регулярные выражения. Теперь давайте рассмотрим процесс создания шаблонов. Простейший способ составлять регулярные выражения —применение простых шаблонов. Это значит, что необходимо создать строку с особым текстом, а затем проверить, имеет ли какая-то другая строка совпадения с этим текстом.
// Создание простого шаблона// с использованием литерала регулярного выраженияconst myPattern = /JavaScript/// Проверка строки на совпадения с шаблономmyPattern.test('One of the most popular languages is also JavaScript.')// true// Проверка строки на совпадения с шаблономmyPattern.test('What happens if you combine Java with scripting?')// false
Как создавать сложные шаблоны со специальными символами?
До сих пор мы использовали регулярные выражения из простых шаблонов. Их может быть достаточно для каких-то простых задач. Однако для сложных случаев такие выражения не подойдут. Настало время создавать и использовать более сложные шаблоны. Здесь в игру вступают специальные символы. Давайте рассмотрим те из них, которые наиболее часто используются в регулярных выражениях.