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

JavaScript regexp – это тип объекта, который используется для сопоставления последовательности символов в строках.

Создаем первое регулярное выражение

Существует два способа создания регулярного выражения: с использованием литерала регулярного выражения или с помощью конструктора регулярных выражений. Каждый из них представляет один и тот же шаблон: символ «c», за которым следует «a», а затем символ «t».

// литерал регулярного выражения заключается в слэши (/)
var option1 = /cat/;
// Конструктор регулярнго выражения
var option2 = new RegExp("cat");

Как правило, если регулярное выражение остается константой, то есть не будет меняться, лучше использовать литерал регулярного выражения. Если оно будет меняться или зависит от других переменных, лучше использовать метод с конструктором.

Метод RegExp.prototype.test()

Помните, я говорил, что регулярные выражения являются объектами? Это означает, что у них есть ряд методов. Самый простой метод – это JavaScript regexp test, который возвращает логическое значение:

True (истина): строка содержит шаблон регулярного выражения.

False (ложь): совпадения не найдено.

console.log(/cat/.test(“the cat says meow”));
// верно
console.log(/cat/.test(“the dog says bark”));
// неверно

Памятка по основам регулярных выражений

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

Символы

  • . – (точка) соответствует любому одиночному символу за исключением переноса строки;
  • * –  соответствует предыдущему выражению, которое повторяется 0 или более раз;
  • + –  соответствует предыдущему выражению, которое повторяется 1 или более раз;
  • ? –  предыдущее выражение является необязательным (соответствует 0 или 1 раз);
  • ^ – соответствует началу строки;
  • $ – соответствует концу строки.

Группы символов

  • d –  соответствует любому одиночному цифровому символу.
  • w –  соответствует любому символу (цифре, букве или знаку подчёркивания).
  • [XYZ]  –  набор символов. Соответствует любому одиночному символу из набора, заданного в скобках. Также можно задавать и диапазоны символов, например,[A-Z].
  • [XYZ]+  –  соответствует символу из набора, повторяемого один или более раз.
  • [^AZ]  –  внутри набора символов «^» используется как знак отрицания. В данном примере шаблону соответствует всё, что не является буквами в верхнем регистре.

Флаги:

В JavaScript regexp существует пять необязательных флагов. Они могут использоваться отдельно или вместе, и размещаются после закрывающего слеша. Например: /[AZ]/g. Здесь я приведу только два флага.

g –  глобальный поиск.

i –  поиск, нечувствительный к регистру.

Дополнительные конструкции

(x)  –   захватывающие скобки. Это выражение соответствует x и запоминает это соответствие, поэтому им можно воспользоваться позже.

(?:x)  –  незахватывающие скобки. Выражение соответствует x, но не запоминает это соответствие.

Соответствует x, только если за ним следует y.

Протестируем изученный материал

Сначала протестируем все выше сказанное. Допустим, что мы хотим проверить строку на наличие любых цифр. Для этого можно использовать конструкцию «d».

console.log(/d/.test('12-34'));
// верно

Приведенный выше код возвращает значение true, если в строке есть хотя бы одна цифра. Что делать, если нужно проверить строку на соответствие формату? Можно использовать несколько символов «d», чтобы определить формат:

console.log(/dd-dd/.test('12-34'));
//верно
console.log(/dd-dd/.test('1234'));
//неверно

Если неважно, как в JavaScript regexp online идут цифры до и после знака «», можно использовать символ «+», чтобы показать, что шаблон «d» встречается один или несколько раз:

console.log(/d+-d+/.test('12-34'));
// верно
console.log(/d+-d+/.test('1-234'));
// верно
console.log(/d+-d+/.test('-34'));
// неверно

Для простоты можно использовать скобки, чтобы сгруппировать выражения. Допустим, у нас есть мяуканье кошки, и мы хотим проверить соответствие шаблону «meow» (мяу):

console.log(/me+(ow)+w/.test('meeeeowowoww'));
// верно

Теперь давайте разберемся.

/me+(ow)+w/

m => соответствие одной букве ‘m‘;

e + => соответствие букве «e» один или несколько раз;

(ow) + => соответствие буквам «ow» один или несколько раз;

w => соответствие букве ‘w’;

‘m’ + ‘eeee’ + ‘owowow’ + ‘w’.

Когда операторы типа «+» используются сразу после скобок, они влияют на все содержимое скобок.

Оператор «?». Он указывает, что предыдущий символ является необязательным. Как вы увидите ниже, оба тестовых примера возвращают значение true, потому что символы «s» помечены как необязательные.

console.log(/cats? says?/i.test('the Cat says meow'));
//верно
console.log(/cats? says?/i.test('the Cats say meow'));
//верно

Также выше я добавил флаг «/i». Это делает поиск нечувствительным к регистру, поэтому «cats» будут соответствовать «Cats».

Советы и подсказки

Если вы захотите найти символ слеша, нужно экранизировать его с помощью обратного слеша. То же самое верно для других символов, которые имеют особое значение, например, вопросительного знака. Вот JavaScript regexp пример того, как их искать:

var slashSearch = ///;
var questionSearch = /?/;

  • d – это то же самое, что и [0-9]: каждая конструкция соответствует цифровому символу.
  • w – это то же самое, что [AZaz0-9_]: оба выражения соответствуют любому одиночному алфавитно-цифровому символу или подчеркиванию.

Пример: добавляем пробелы в строки, написанные в «верблюжьем» стиле

В этом примере мы очень устали от «верблюжьего» стиля написания и нам нужен способ добавить пробелы между словами. Вот пример:

removeCc('camelCase') // => должен вернуть 'camel Case'

Существует простое решение с использованием регулярного выражения. Во-первых, нам нужно найти все заглавные буквы. Это можно сделать с помощью поиска набора символов и глобального модификатора.

Это соответствует символу «C» в «camelCase»

/[A-Z]/g

Теперь, как добавить пробел перед «C»?

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

/([A-Z])/

Получить доступ к захваченному значению позднее можно так:

$1

Выше мы используем $1 для доступа к захваченному значению. Кстати, если бы у нас было два набора захватывающих скобок, мы использовали бы $1 и $2 для ссылки на захваченные значения и аналогично для большего количества захватывающих скобок.

Если вам нужно использовать скобки, но не нужно фиксировать это значение, можно использовать незахватывающие скобки: (?: x). В этом случае находится соответствие x, но оно не запоминается.

Вернемся к текущей задаче. Как мы реализуем захватывающие скобки? С помощью метода JavaScript regexp replace! В качестве второго аргумента мы передаем «$1». Здесь важно использовать кавычки.

function removeCc(str){
return str.replace(/([A-Z])/g, '$1');
}

Снова посмотрим на код. Мы захватываем прописную букву, а затем заменяем ее той же самой буквой. Внутри кавычек вставим пробел, за которым следует переменная $1. В итоге получаем пробел после каждой заглавной буквы.

function removeCc(str){
return str.replace(/([A-Z])/g, ' $1');
}
removeCc('camelCase') // 'camel Case'
removeCc('helloWorldItIsMe') // 'hello World It Is Me'

Пример: удаляем заглавные буквы

Теперь у нас есть строка с кучей ненужных прописных букв. Вы догадались, как их удалить? Во-первых, нам нужно выбрать все заглавные буквы. Затем используем поиск набора символов с помощью глобального модификатора:

/[A-Z]/g

Мы снова будем использовать метод replace, но как в этот раз сделать строчной символ?

function lowerCase(str){
return str.replace(/[A-Z]/g, ???);
}

Подсказка: в методе replace() в качестве второго параметра можно указать функцию.

Мы будем использовать стрелочную функцию, чтобы не захватывать значение найденного совпадения. При использовании функции в методе JavaScript regexp replace эта функция будет вызвана после поиска совпадений, и результат функции используется в качестве замещающей строки. Еще лучше, если совпадение является глобальным и найдено несколько совпадений — функция будет вызвана для каждого найденного совпадения.

function lowerCase(str){
return str.replace(/[A-Z]/g, (u) => u.toLowerCase());
}
lowerCase('camel Case') // 'camel case'
lowerCase('hello World It Is Me') // 'hello world it is me'

Пример: преобразуем первую букву в заглавную

capitalize('camel case') // => должен вернуть 'Camel case'

Еще раз воспользуемся функцией в методе replace(). Однако на этот раз нам нужно искать только первый символ в строке. Напомним, что для этого используется символ «^».

Давайте на секунду задержимся на символе «^». Вспомните пример, приведенный ранее:

console.log(/cat/.test('the cat says meow'));
//верно

При добавлении символа «^» функция больше не возвращает значение true, поскольку слово «cat» находится не в начале строки:

console.log(/^cat/.test('the cat says meow'));
//неверно

Мы хотим применить символ «^» к любому строчному символу в начале строки, поэтому мы поместим его перед набором символов [a-z]. В этом случае JavaScript regexp будет направлено только на первый символ, если это строчная буква.

/^[a-z]/

Обратите внимание, что мы больше не используем глобальный модификатор, так как нам нужно только одно совпадение. Теперь можно вставить регулярное выражение в метод replace и добавить стрелочную функцию в качестве второго аргумента:

function capitalize(str){
return str.replace(/^[a-z]/, (u) => u.toUpperCase());
}
capitalize('camel case') // 'Camel case'
capitalize('hello world it is me') // 'Hello world it is me'

Продолжаем изучение

На этом наш урок заканчивается, но не заканчивается ваше обучение. Вот несколько идей для проектов:

  1. Можете ли вы объединить предыдущие три функции в одну функцию, которая превращает строку, представленную в «верблюжьем» стиле в обычное предложение?
  2. Можете ли вы добавить точку в конец строки?
  3. Все наоборот! Преобразуйте строку в хэштег, представленный в «верблюжьем» стиле.

Поделитесь своими JavaScript regexp примерами и решениями в комментариях! И не забывайте, что это всего лишь основы регулярных выражений, с ними можно делать гораздо больше!

Перевод статьи «JavaScript: Learn Regular Expressions for Beginners» был подготовлен дружной командой проекта  Сайтостроение от А до Я.