Введение в регулярные выражения в JavaScript


Введение

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

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

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

Как создавать регулярные выражения?

Если с помощью JavaScript вы хотите создать регулярное выражение (описать шаблон), есть два способа это сделать.

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

Первый способ — использование конструктора. Это громкое слово на самом деле означает функцию-конструктор объекта RegExp. Конструктор принимает два параметра. Первый — шаблон, который вы хотите описать. Это обязательный параметр. В конце концов, зачем вообще создавать регулярное выражение, если нет шаблона?

Второй параметр — строка с флагами (flags). Не волнуйтесь, скоро мы с ними познакомимся. Этот параметр необязательный. Стоит запомнить одно: после создания регулярного выражения флаги уже нельзя будет добавить или убрать. Поэтому, если хотите использовать флаг, добавьте его на этапе создания выражения.

// Синтаксис конструктора регулярных выражений new RegExp(pattern[, flags]) // Создание регулярного выражения // с помощью конструктора // без флагов const myPattern = new RegExp('[a-z]') // Создание регулярного выражения // с помощью конструктора // с одним флагом const myPattern = new RegExp('[a-z]', 'g') Литерал регулярных выражений

Второй способ — использование литерала. Как и конструктор, литерал регулярных выражений состоит из двух частей. Первая часть — это описываемый шаблон. Он заключается в слэши (//). После закрывающего слэша идёт вторая часть — флаги. Они необязательны.

// Синтаксис литерала регулярных выражений /pattern/flags // Создание регулярного выражения // с помощью литерала // без флагов const myPattern = /[a-z]/ // Создание регулярного выражения // с помощью литерала // с одним флагом const myPattern = /[a-z]/g

Примечание: два слэша в литерале регулярных выражений используются для того, чтобы заключить в них шаблон. Если ваш шаблон предполагает использование ещё одного или нескольких прямых слэшей, их необходимо экранировать обратным слэшем (\), то есть \ /.

Конструктор или литерал?

Конструктор и литерал выполняют одну функцию, но есть одно важное различие. Регулярное выражение, созданное при помощи конструктора, компилируется при выполнении программы, литерал — на этапе загрузки скрипта. Это значит, что литерал нельзя изменить динамически, в то время как конструктор — можно.

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

Как использовать регулярные выражения с методами объекта RegExp?

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

test()

Для работы с регулярными выражениями есть несколько методов. Простейший из них — test(). При использовании этого метода необходимо передать функции проверяемую строку в качестве аргумента. В результате метод возвращает булево значение: true — если в строке есть совпадения с шаблоном, false — если совпадений нет.

// Синтаксис метода test() // /шаблон/.test('проверяемый текст') // Проверка строки, // когда test() не находит совпадений myPattern.test('There was a cat and dog in the house.') // false // Создание переменной, // которой присваивается текст для проверки const myString = 'The world of code.'  // Создание шаблона const myPattern = /code/ // Проверка текста с помощью шаблона, // когда test() находит совпадение myPattern.test(myString) // true exec()

Ещё один метод, который можно использовать — exec(). Если есть совпадение, метод exec() возвращает массив. Массив содержит в себе информацию об используемом шаблоне, позиции, на которой было найдено совпадение, проверяемом тексте и наборах. Если совпадений нет, метод exec() возвращает null.

Необходимо запомнить одну вещь: метод exec() возвращает информацию только о первом найденном в тексте совпадении. Он прекращает работу после нахождения первого совпадения. Не используйте этот метод, если хотите получить множественные совпадения.

// Синтаксис метода exec() // /шаблон/.exec('проверяемый текст') // Создание строки для проверки const myString = 'The world of code is not full of code.' // Описание шаблона const myPattern = /code/ // Использование exec() для проверки текста, // когда exec() находит совпадение myPattern.exec(myString) // [ // 'code', // index: 13, // input: 'The world of code is not full of code.', // groups: undefined // ] // Описание другого шаблона const myPatternTwo = /JavaScript/ // Использование exec() с новым шаблоном для новой проверки текста, // когда exec() не находит совпадений myPatternTwo.exec(myString) // null

Как использовать регулярные выражения с методами объекта String?

test() и exec() — не единственные методы, которые можно использовать для поиска совпадений строки с шаблоном. Есть ещё search(), match() и matchAll(). Эти методы принадлежат не объекту RegExp, а строкам. Несмотря на это, они позволяют применять регулярные выражения.

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

search()

Первый метод, search(), ищет в строке заданный шаблон. Если он находит совпадение, то возвращает позицию в строке, где это совпадение начинается. Если совпадения нет, возвращается -1. Нужно запомнить, что метод 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 match()

match() — второй метод объекта String, который позволяет использовать регулярные выражения. Он работает аналогично exec(): при нахождении совпадения метод match() возвращает массив с информацией об использованном шаблоне, позиции в строке, на которой было найдено совпадение, проверяемом тексте и наборах.

Так же как и exec(), match() возвращает null при отсутствии совпадений. При использовании метода match() с флагом g для поиска всех совпадений с шаблоном возвращается массив из всех совпадений.

// Синтаксис метода match() // 'проверяемый текст'.match(/шаблон/) // Создание текста для проверки const myString = 'The world of code is not full of code.' // Описание шаблона const myPattern = /code/ // Использование match() для поиска совпадения в тексте myString.match(myPattern) // [ // 'code', // index: 13, // input: 'The world of code is not full of code.', // groups: undefined // ] 'Another day in the life.'.match(myPattern) // null // Использование match() для поиска всех совпадений // Создание текста для проверки const myString = 'The world of code is not full of code.' // Описание шаблона const myPattern = /code/g // добавление флага 'g' // Использование match() для поиска совпадения в тексте myString.match(myPattern) // [ 'code', 'code' ] matchAll()

Подобно методу match(), matchAll() возвращает все совпадения при использовании флага g в шаблоне. Однако работает он по-другому. Метод matchAll() возвращает объект RegExp String Iterator. Есть несколько способов извлечь из него все совпадения.

Во-первых, можно пройтись по объекту циклом for…of и вернуть или записать все совпадения. Также можно использовать Array.from(), чтобы создать массив из содержимого объекта, или оператор spread, который даст точно такой же результат, как и Array.from().

// Синтаксис метода 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 = [...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 // ] // ]

Как создавать простые шаблоны?

Вы узнали, как создавать и использовать регулярные выражения. Теперь давайте рассмотрим процесс создания шаблонов. Простейший способ составлять регулярные выражения —применение простых шаблонов. Это значит, что необходимо создать строку с особым текстом, а затем проверить, имеет ли какая-то другая строка совпадения с этим текстом.

// Создание простого шаблона // с использованием литерала регулярного выражения 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

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

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

Символьные классы

Символьные классы — это своеобразные сокращения для разных типов символов. К примеру, есть свои классы для букв, цифр, пробелов и т. д.

/* Символьный класс - Значение */ . - любой символ, кроме первой строки \d - одноразрядное число (то же, что и [0-9]) \w - отдельный буквенно-числовой словообразующий символ из латинского алфавита, включая подчёркивание (то же, что и [A-Za-z0-9_) \s - отдельный символ разделителя (пробел, табуляция и т. п.) (то же, что и [\t\r\n\v\f]) \D - отдельный нечисловой символ (то же, что и[^0-9]) \W - отдельный несловообразующий символ из латинского алфавита (то же, что и [^A-Za-z0-9_]) \S - отдельный символ, который не является разделителем (то же, что и [^\t\r\n\v\f]).

Примеры:

// . - любой символ, кроме первой строки const myPattern = /./ console.log(myPattern.test('')) // false console.log(myPattern.test('word')) // true console.log(myPattern.test('9')) // true // \d - одноразрядное число const myPattern = /\d/ console.log(myPattern.test('3')) // true console.log(myPattern.test('word')) // false // \w - отдельный буквенно-числовой словообразующий символ const myPattern = /\w/ console.log(myPattern.test('')) // false console.log(myPattern.test('word')) // true console.log(myPattern.test('9')) // true // \s - отдельный символ разделителя const myPattern = /\s/ console.log(myPattern.test('')) // false console.log(myPattern.test(' ')) // true console.log(myPattern.test('foo')) // false // \D - отдельный нечисловой символ const myPattern = /\D/ console.log(myPattern.test('Worm')) // true console.log(myPattern.test('1')) // false // \W - отдельный несловообразующий символ const myPattern = /\W/ console.log(myPattern.test('Worm')) // false console.log(myPattern.test('1')) // false console.log(myPattern.test('*')) // true console.log(myPattern.test(' ')) // true // \S - отдельный символ, который не является разделителем const myPattern = /\S/ console.log(myPattern.test('clap')) // true console.log(myPattern.test('')) // false console.log(myPattern.test('-')) // true Операторы контроля

Ещё один вид специальных символов — это операторы контроля. Такие символы позволяют описывать шаблоны с границами, то есть указывать, где начинается или заканчивается слово или строка. С помощью операторов контроля также можно создавать более сложные шаблоны, такие как опережающие проверки, ретроспективные проверки и условные выражения.

/* Оператор контроля - Значение */ ^ - начало строки (последующее регулярное выражение должно совпадать с началом проверяемой строки). $ - конец строки (последующее регулярное выражение должно совпадать с концом проверяемой строки). \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')) // false console.log(myPattern.test('read')) // true console.log(myPattern.test('real')) // true console.log(myPattern.test('free')) // false // $ - Конец строки const myPattern = /ne$/ console.log(myPattern.test('all is done')) // true console.log(myPattern.test('on the phone')) // true console.log(myPattern.test('in Rome')) // false console.log(myPattern.test('Buy toner')) // false // \b - Граница слова const myPattern = /\bro/ console.log(myPattern.test('road')) // true console.log(myPattern.test('steep')) // false console.log(myPattern.test('umbro')) // false // Или const myPattern = /\btea\b/ console.log(myPattern.test('tea')) // true console.log(myPattern.test('steap')) // false console.log(myPattern.test('tear')) // false // \B - Несловообразующая граница const myPattern = /\Btea\B/ console.log(myPattern.test('tea')) // false console.log(myPattern.test('steap')) // true console.log(myPattern.test('tear')) // false // x(?=y) - Опережающая проверка const myPattern = /doo(?=dle)/ console.log(myPattern.test('poodle')) // false console.log(myPattern.test('doodle')) // true console.log(myPattern.test('moodle')) // false // x(?!y) - Негативная опережающая проверка const myPattern = /gl(?!u)/ console.log(myPattern.test('glue')) // false console.log(myPattern.test('gleam')) // true // (?<=y)x - Ретроспективная проверка const myPattern = /(?<=re)a/ console.log(myPattern.test('realm')) // true console.log(myPattern.test('read')) // true console.log(myPattern.test('rest')) // false // (?<!y)x - Негативная ретроспективная проверка const myPattern = /(?<!re)a/ console.log(myPattern.test('break')) // false console.log(myPattern.test('treat')) // false console.log(myPattern.test('take')) // true Квантификаторы

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

/* Квантификатор - Значение */ * - 0 или более совпадений с предшествующим выражением. + - 1 или более совпадений с предшествующим выражением. ? - Предшествующее выражение необязательно (то есть совпадений 0 или 1). x{n} - "n" должно быть целым положительным числом. Количество вхождений предшествующего выражения "x" равно "n". x{n, } - "n" должно быть целым положительным числом. Количество вхождений предшествующего выражения "x" равно, как минимум, "n". x{n, m} - "n" может быть равно 0 или целому положительному числу. "m" - целое положительное число. Если "m" > "n", количество вхождений предшествующего выражения "x" равно минимум "n" и максимум "m".

Примеры:

// * - 0 или более совпадений с предшествующим выражением const myPattern = /bo*k/ console.log(myPattern.test('b')) // false console.log(myPattern.test('bk')) // true console.log(myPattern.test('bok')) // true // + - 1 или более совпадений с предшествующим выражением const myPattern = /\d+/ console.log(myPattern.test('word')) // false console.log(myPattern.test(13)) // true // ? - Предшествующее выражение необязательно, совпадений 0 или 1 const myPattern = /foo?bar/ console.log(myPattern.test('foobar')) // true console.log(myPattern.test('fooobar')) // false // x{n} - Количество вхождений предшествующего выражения "x" равно "n" const myPattern = /bo{2}m/ console.log(myPattern.test('bom')) // false console.log(myPattern.test('boom')) // true console.log(myPattern.test('booom')) // false // x{n, } - Количество вхождений предшествующего выражения "x" равно, как минимум, "n" const myPattern = /do{2,}r/ console.log(myPattern.test('dor')) // false console.log(myPattern.test('door')) // true console.log(myPattern.test('dooor')) // true // x{n, m} - Количество вхождений предшествующего выражения "x" равно минимум "n" и максимум "m" const myPattern = /zo{1,3}m/ console.log(myPattern.test('zom')) // false console.log(myPattern.test('zoom')) // true console.log(myPattern.test('zooom')) // true console.log(myPattern.test('zoooom')) // false Наборы и диапазоны

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

/* Набор или диапазон - Значение */ [abc] - любой один из символов в скобках. [^abc] — любой символ, за исключением символов в скобках. [a-z] - любой символ в диапазоне от "a" до "z". [^a-z] - любой символ не из диапазона от "a" до "z". (x) - "x", значение запоминается для дальнейшего использования. (?<name>x) - создание именованной скобочной группы, к которой можно обратиться по указанному имени. (?:x) - "x", значение не запоминается, поэтому совпадение невозможно извлечь из итогового массива элементов.

Примеры:

// [abc] - Любой один из символов в скобках. const myPattern = /[aei]/ console.log(myPattern.test('aei')) // true (есть a, e, i) console.log(myPattern.test('form')) // false (нет a, e или i) // [^abc] - Любой символ, за исключением символов в скобках. const myPattern = /[^aei]/ console.log(myPattern.test('aei')) // false (нет других символов, кроме a, e и i) console.log(myPattern.test('form')) // true (есть другие символы, кроме a, e и i) // [a-z] - Любой символ в диапазоне от "a" до "z". const myPattern = /[b-g]/ console.log(myPattern.test('bcd')) // true (есть символы в диапазоне от 'b' до 'g') console.log(myPattern.test('jklm')) // false (нет символов в диапазоне от 'b' до 'g') // [^a-z] - Любой символ не из диапазона от "a" до "z". const myPattern = /[^b-g]/ console.log(myPattern.test('bcd')) // false (нет других символов, кроме входящих в диапазон от 'b' до 'g') console.log(myPattern.test('jklm')) // true (есть другие символы, кроме входящих в диапазон от 'b' до 'g') // (x) - "x", значение запоминается для дальнейшего использования. const myPattern = /(na)da\1/ console.log(myPattern.test('nadana')) // true - \1 запоминает и использует совпадение 'na' из первого выражения в скобках. console.log(myPattern.test('nada')) // false // (?<name>x) - Создание именованной скобочной группы, к которой можно обратиться по указанному имени. const myPattern = /(?<foo>is)/ console.log(myPattern.test('Work is created.')) // true console.log(myPattern.test('Just a text')) // false // (?:x) - "x", значение не запоминается. const myPattern = /(?:war)/ console.log(myPattern.test('warsawwar')) // true console.log(myPattern.test('arsaw')) // false Альтернация

Альтернация позволяет находить соответствие, по крайней мере, одному из нескольких выражений.

/* Альтернация - Значение */ | - выражение до или после символа |, как в булевом ИЛИ (||).

Примеры:

// | - Выражение до или после символа | const myPattern = /(black|white)swan/ console.log(myPattern.test('black swan')) // true console.log(myPattern.test('white swan')) // true console.log(myPattern.test('gray swan')) // false Флаги

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

/* Флаг - Значение */ g – Глобальный поиск, не останавливается после нахождения первого совпадения. i – Игнорирование регистра (соответствует верхнему и нижнему регистрам). s - Точка (.) соответствует переводу на новую строку. m – Многострочный ввод, начинается с "^" и заканчивается "$" (начало и конец каждой строки).

Примеры:

// флаг g - Глобальный поиск const myPattern = /xyz/g console.log(myPattern.test('One xyz and one more xyz')) // true // флаг i - Игнорирование регистра const myPattern = /xyz/i console.log(myPattern.test('XyZ')) // true - регистр символов не имеет значения при нечувствительном к регистру поиске.  // флаг s - Точка (.) соответствует переводу на новую строку const myPattern = /foo.bar/s console.log(myPattern.test('foo\nbar')) // true console.log(myPattern.test('foo bar')) // true console.log(myPattern.test('foobar')) // false

Заключение

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


Перевод статьи Alex Devero: Introduction to Regular Expressions in JavaScript


Поделиться статьей:


Вернуться к статьям

Комментарии

    Ничего не найдено.