Javascript для начинающих: изучаем регулярные выражения

Методы 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

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

Метод , если у регулярного выражения нет флага , ищет первое совпадение и возвращает его в виде массива:

  1. На позиции будет всё совпадение целиком.
  2. На позиции – содержимое первой скобочной группы.
  3. На позиции – содержимое второй скобочной группы.
  4. …и так далее…

Например, мы хотим найти HTML теги и обработать их. Было бы удобно иметь содержимое тега (то, что внутри уголков) в отдельной переменной.

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

Теперь получим как тег целиком , так и его содержимое в виде массива:

Скобки могут быть и вложенными.

Например, при поиске тега в нас может интересовать:

  1. Содержимое тега целиком: .
  2. Название тега: .
  3. Атрибуты тега: .

Заключим их в скобки в шаблоне: .

Вот их номера (слева направо, по открывающей скобке):

В действии:

По нулевому индексу в всегда идёт полное совпадение.

Затем следуют группы, нумеруемые слева направо, по открывающим скобкам. Группа, открывающая скобка которой идёт первой, получает первый индекс в результате – . Там находится всё содержимое тега.

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

Соответствие для каждой группы в строке:

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

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

Если применить его к строке из одной буквы , то результат будет такой:

Массив имеет длину , но все скобочные группы пустые.

А теперь более сложная ситуация для строки :

Длина массива всегда равна . Для группы ничего нет, поэтому результат: .

Проверка наличия совпадения

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

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

Как создавать сложные шаблоны со специальными символами?

До сих пор мы использовали регулярные выражения из простых шаблонов. Их может быть достаточно для каких-то простых задач. Однако для сложных случаев такие выражения не подойдут. Настало время создавать и использовать более сложные шаблоны. Здесь в игру вступают специальные символы. Давайте рассмотрим те из них, которые наиболее часто используются в регулярных выражениях.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector