Быстрое и простое руководство по регулярным выражениям JavaScript

1656621856 bystroe i prostoe rukovodstvo po regulyarnym vyrazheniyam javascript

Интересно изучать JavaScript? Получите мою электронную книгу на jshandbook.com

Знакомство с регулярными выражениями

Регулярное выражение (также называется регулярное выражение кратко) — это быстрый способ работы со строчками текста.

Сформулируя регулярное выражение со специальным синтаксисом, вы можете:

  • поиск текста в строке
  • заменить подстроки в строке
  • и извлекать информацию из струны

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

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

Реализованные в инструментах UNIX, таких как grep, sed и в популярных текстовых редакторах, регулярные выражения выросли в популярности. Они были введены в язык программирования Perl, а затем и во многих других.

JavaScript, наряду с Perl, является одним из языков программирования, поддерживающим регулярные выражения, непосредственно встроенные в язык.

Трудно, но полезно

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

Загадочные регулярные выражения трудно писать, трудно читатьи трудно поддерживать/изменять.

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

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

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

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

В JavaScript регулярным выражением является объекткоторый можно определить двумя способами.

Первый – создание экземпляра a новый объект RegExp с помощью конструктора:

const re1 = new RegExp('hey')

Второй – использование регулярное выражение форма:

const re1 = /hey/

Вы знаете, что JavaScript есть объектные литералы и литералы массива? Он также имеет регулярные выражения.

В приведенном выше примере hey называется узор. В буквальной форме он разграничен косыми чертами, тогда как в конструкторе объектов – нет.

Это первое важное различие между двумя формами, но другие мы увидим позже.

Как это работает?

Регулярное выражение, которое мы определили как re1 выше очень простой. Он ищет строчку hey, без каких-либо ограничений. Строка может содержать много текста и hey посередине, и регулярное выражение удовлетворено. Он также может содержать только heyи регулярное выражение также будет удовлетворено.

Это достаточно просто.

Вы можете проверить регулярное выражение с помощью RegExp.test(String)возвращающий логическое значение:

re1.test('hey') //✅ re1.test('blablabla hey blablabla') //✅ re1.test('he') //❌ re1.test('blablabla') //❌

В приведенном выше примере мы просто проверили, если "hey" удовлетворяет сохраняемому шаблону регулярных выражений re1.

Это самое простое, но теперь вы уже знаете много понятий о регулярных выражениях.

Якоря

/hey/

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

Если вы хотите сопоставить строки, что начать с heyиспользовать ^ оператор:

/^hey/.test('hey') //✅ /^hey/.test('bla hey') //❌

Если вы хотите сопоставить строки, что конец с heyиспользовать $ оператор:

/hey$/.test('hey') //✅ /hey$/.test('bla hey') //✅ /hey$/.test('hey you') //❌

Объедините их и соберите точно соответствующие строки heyи только эта строка:

/^hey$/.test('hey') //✅

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

/^hey.*joe$/.test('hey joe') //✅ /^hey.*joe$/.test('heyjoe') //✅ /^hey.*joe$/.test('hey how are you joe') //✅ /^hey.*joe$/.test('hey joe!') //❌

Сопоставьте предметы в диапазонах

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

/[a-z]/ //a, b, c, ... , x, y, z /[A-Z]/ //A, B, C, ... , X, Y, Z /[a-c]/ //a, b, c /[0-9]/ //0, 1, 2, 3, ... , 8, 9

Эти регулярные выражения соответствуют строкам, содержащим, по крайней мере, один из символов в этих диапазонах:

/[a-z]/.test('a') //✅ /[a-z]/.test('1') //❌ /[a-z]/.test('A') //❌ /[a-c]/.test('d') //❌ /[a-c]/.test('dc') //✅

Диапазоны можно комбинировать:

/[A-Za-z0-9]/
/[A-Za-z0-9]/.test('a') //✅ /[A-Za-z0-9]/.test('1') //✅ /[A-Za-z0-9]/.test('A') //✅

Совпадение элемента диапазона несколько раз

Вы можете проверить, содержит ли строка один и только один символ в диапазоне, используя - char:

/^[A-Za-z0-9]$/ 
/^[A-Za-z0-9]$/.test('A') //✅ /^[A-Za-z0-9]$/.test('Ab') //❌

Возражение шаблона

The ^ символ в начале шаблона привязывает его к началу строки.

Используется внутри диапазона, it возражает это, следовательно:

/[^A-Za-z0-9]/.test('a') //❌ /[^A-Za-z0-9]/.test('1') //❌ /[^A-Za-z0-9]/.test('A') //❌ /[^A-Za-z0-9]/.test('@') //✅
  • \d соответствует любой цифре, эквивалентной [0-9]
  • \D соответствует любому символу, не являющемуся цифрой, эквивалентный [^0-9]
  • \w соответствует любому буквенно-цифровому символу, эквивалентному [A-Za-z0-9]
  • \W соответствует любому небуквенно-цифровому символу, эквивалентному [^A-Za-z0-9]
  • \s соответствует любому пробелу: пробелов, табуляций, новой строки и пробелов Unicode
  • \S соответствует любому символу, не являющемуся пробелом
  • \0 соответствует нулю
  • \n соответствует символу новой строки
  • \t соответствует символу табуляции
  • \uXXXX соответствует символу Unicode с кодом XXXX (нужно u флаг)
  • . соответствует любому символу, не являющемуся символом новой строки (например \n) (если вы не используете s флаг, объясняется позже)
  • [^] соответствует любому символу, включая символы новой строки. Это полезно для многострочных строк.

Выбор регулярных выражений

Если вы хотите искать одну строчку или другой, используйте | оператор.

/hey|ho/.test('hey') //✅ /hey|ho/.test('ho') //✅

Кванторы

Скажем, у вас есть это регулярное выражение, которое проверяет, содержит ли строку одну цифру, и ничего больше:

/^\d$/

Вы можете использовать в ? квантор чтобы сделать его необязательным, таким образом требуя нуля или единицы:

/^\d?$/

но что если вы хотите сопоставить несколько цифр?

Сделать это можно 4 способами, используя +, *, {n} и {n,m}. Давайте посмотрим на эти один за другим.

+

Установите соответствие одному или нескольким (>=1) элементам

/^\d+$/ 
/^\d+$/.test('12') //✅ /^\d+$/.test('14') //✅ /^\d+$/.test('144343') //✅ /^\d+$/.test('') //❌ /^\d+$/.test('1a') //❌

*

Найдите 0 или более (>=0) элементов

/^\d+$/ 
/^\d*$/.test('12') //✅ /^\d*$/.test('14') //✅ /^\d*$/.test('144343') //✅ /^\d*$/.test('') //✅ /^\d*$/.test('1a') //❌

{n}

Точно совпадают n предметов

/^\d{3}$/ 
/^\d{3}$/.test('123') //✅ /^\d{3}$/.test('12') //❌ /^\d{3}$/.test('1234') //❌ /^[A-Za-z0-9]{3}$/.test('Abc') //✅

{n,m}

Матч между n и m раз:

/^\d{3,5}$/ 
/^\d{3,5}$/.test('123') //✅ /^\d{3,5}$/.test('1234') //✅ /^\d{3,5}$/.test('12345') //✅ /^\d{3,5}$/.test('123456') //❌

m можно опустить, чтобы иметь открытый конец, и у вас есть по крайней мере n предметы:

/^\d{3,}$/ 
/^\d{3,}$/.test('12') //❌ /^\d{3,}$/.test('123') //✅ /^\d{3,}$/.test('12345') //✅ /^\d{3,}$/.test('123456789') //✅

Дополнительные элементы

После элемента из ? делает его необязательным:

/^\d{3}\w?$/ 
/^\d{3}\w?$/.test('123') //✅ /^\d{3}\w?$/.test('123a') //✅ /^\d{3}\w?$/.test('123ab') //❌

Группы

С помощью скобок можно создать группы символов: (...)

Этот пример соответствует точно 3 цифрам, за которыми следуют один или несколько буквенно-цифровых символов:

/^(\d{3})(\w+)$/ 
/^(\d{3})(\w+)$/.test('123') //❌ /^(\d{3})(\w+)$/.test('123s') //✅ /^(\d{3})(\w+)$/.test('123something') //✅ /^(\d{3})(\w+)$/.test('1234') //✅

Символы повторения, размещенные после закрывающих скобок группы, относятся ко всей группе:

/^(\d{2})+$/ 
/^(\d{2})+$/.test('12') //✅ /^(\d{2})+$/.test('123') //❌ /^(\d{2})+$/.test('1234') //✅

Увлечения групп

Пока мы видели, как проверить строки и проверить, содержат ли они определенный шаблон.

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

Вы можете сделать это с помощью Групп, в частности Увлечения групп.

По умолчанию группа является группой увлечения. Теперь вместо использования RegExp.test(String)который просто возвращает логическое значение, если шаблон удовлетворяется, мы используем любой String.match(RegExp) или RegExp.exec(String).

Они абсолютно одинаковы и возвращают массив с целой соответствующей строкой в ​​первом элементе, а затем содержимым каждой группы.

Если совпадения нет, он возвращается null:

'123s'.match(/^(\d{3})(\w+)$/) //Array [ "123s", "123", "s" ] 
/^(\d{3})(\w+)$/.exec('123s') //Array [ "123s", "123", "s" ] 
'hey'.match(/(hey|ho)/) //Array [ "hey", "hey" ] 
/(hey|ho)/.exec('hey') //Array [ "hey", "hey" ] 
/(hey|ho)/.exec('ha!') //null

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

'123456789'.match(/(\d)+/) //Array [ "123456789", "9" ]

Факультативные группы

Группу захвата можно сделать необязательной с помощью (...)?. Если он не найден, полученный слот массива будет содержать undefined:

/^(\d{3})(\s)?(\w+)$/.exec('123 s') //Array [ "123 s", "123", " ", "s" ] 
/^(\d{3})(\s)?(\w+)$/.exec('123s') //Array [ "123s", "123", undefined, "s" ]

Ссылки соответствующих групп

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

Названные группы увлечения

Это новая функция ES2018.

Группе можно назначить имя, а не просто назначить слот в полученном массиве:

const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/ const result = re.exec('2015-01-02') 
// result.groups.year === '2015'; // result.groups.month === '01'; // result.groups.day === '02';
O7t7h0vXGY1EDMe6jWKDV7K-K7QZskPzCcGs

Использование match и exec без групп

Существует разница между использованием match и exec без групп: первым элементом массива является не вся соответствующая строка, а непосредственно соответствующая:

/hey|ho/.exec('hey') // [ "hey" ] 
/(hey).(ho)/.exec('hey ho') // [ "hey ho", "hey", "ho" ]

Группы без увлечения

Поскольку по умолчанию группа является группой захвата, вам нужен способ игнорировать некоторые группы в полученном массиве. Это возможно с помощью Группы без увлечениякоторые начинаются на а (?:...)

'123s'.match(/^(\d{3})(?:\s)(\w+)$/)//null 
'123 s'.match(/^(\d{3})(?:\s)(\w+)$/) //Array [ "123 s", "123", "s" ]

Флаги

Вы можете использовать следующие флажки для любого регулярного выражения:

  • g: соответствует шаблону несколько раз
  • i: делает регулярное выражение нечувствительным к регистру.
  • m: включает многострочный режим. В этом режиме ^ и $ соответствовать началу и концу всей строки. Без этого многострочные строчки совпадают с началом и концом каждой строки.
  • u: включает поддержку Unicode (введено в ES6/ES2015)
  • s: (новое в ES2018) сокращение от одна строкаэто вызывает . также соответствовать символам новой строки.

Флаги можно комбинировать, и они добавляются в конец строки в литералах регулярного выражения:

/hey/ig.test('HEy') //✅

или как второй параметр с конструкторами объектов RegExp:

new RegExp('hey', 'ig').test('HEy') //✅

Проверка регулярного выражения

Учитывая регулярное выражение, вы можете проверить его свойства:

  • source строка узора
  • multiline правда с m флаг
  • global правда с g флаг
  • ignoreCase правда с i флаг
  • lastIndex
/^(\w{3})$/i.source //"^(\\d{3})(\\w+)$" /^(\w{3})$/i.multiline //false /^(\w{3})$/i.lastIndex //0 /^(\w{3})$/i.ignoreCase //true /^(\w{3})$/i.global //false

Бегство

Эти символы особые:

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

/^\\$/ /^\^$/ // /^\^$/.test('^') ✅ /^\$$/ // /^\$$/.test('$') ✅

Пределы строки

\b и \B позволяет проверить, находится ли строка в начале или конце слова:

  • \b соответствует набору символов в начале или конце слова
  • \B соответствует набору символов не в начале или конце слова

пример:

'I saw a bear'.match(/\bbear/) //Array ["bear"] 'I saw a beard'.match(/\bbear/) //Array ["bear"] 'I saw a beard'.match(/\bbear\b/) //null 'cool_bear'.match(/\bbear\b/) //null

Заменить, используя регулярные выражения

Мы уже видели, как проверить, содержит ли строку шаблон.

Мы также видели, как вытаскивать части строки в массив, соответствуя шаблону.

Давайте посмотрим, как заменить части струны на основе шаблона.

The String объект в JavaScript имеет метод replace(), который можно использовать без регулярных выражений для выполнения a разовая замена на нити:

"Hello world!".replace('world', 'dog') //Hello dog! 
"My dog is a good dog!".replace('dog', 'cat') //My cat is a good dog!

Этот метод также принимает регулярное выражение как аргумент:

"Hello world!".replace(/world/, 'dog') //Hello dog!

Использование g флаг есть единственный путь чтобы заменить несколько входов в строку в ванильном JavaScript:

"My dog is a good dog!".replace(/dog/g, 'cat') //My cat is a good cat!

Группы позволяют нам делать более причудливые вещи, например, перемещаться по частям строки:

"Hello, world!".replace(/(\w+), (\w+)!/, '$2: $1!!!') // "world: Hello!!!"

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

"Hello, world!".replace(/(\w+), (\w+)!/, (matchedString, first, second) => {   console.log(first);   console.log(second); 
  return `${second.toUpperCase()}: ${first}!!!` }) 
//"WORLD: Hello!!!"

Жадность

Регулярные выражения называются жадный по умолчанию.

Что это значит?

Возьмите это регулярное выражение:

/\$(.+)\s?/

Предполагается извлечь сумму в долларах из строки:

/\$(.+)\s?/.exec('This costs $100')[1] //100

но если у нас есть больше слов после числа, это испугается:

/\$(.+)\s?/.exec('This costs $100 and it is less than $200')[1] //100 and it is less than $200

Почему? Поскольку регулярное выражение после знака $ соответствует любому символу из .+, и он не остановится, пока не достигнет конца строки. Затем это заканчивается, потому что \s? делает конечное пространство необязательным.

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

/\$(.+?)\s/.exec('This costs $100 and it is less than $200')[1] //100

Я удалил ? после \s . Иначе он соответствовал только первому числу, поскольку пробел был необязательным

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

Lookaheads: соответствие строки в зависимости от того, что следует за ней

Используйте ?= чтобы отвечать строке, за которой следует определенная подстрока:

/Roger(?=Waters)/ 
/Roger(?= Waters)/.test('Roger is my dog') //false /Roger(?= Waters)/.test('Roger is my dog and Roger Waters is a famous musician') //true

?! выполняет обратную операцию, совпадая, если строка есть нет за которым следует конкретная подстрока:

/Roger(?!Waters)/ 
/Roger(?! Waters)/.test('Roger is my dog') //true /Roger(?! Waters)/.test('Roger Waters is a famous musician') //false

Lookbehinds: соответствие строки в зависимости от того, что ему предшествует

Это функция ES2018.

Предупреждения используют ?= символ. Использование обзора сзади ?&lt;=.

/(?<=Roger) Waters/ 
/(?<=Roger) Waters/.test('Pink Waters is my dog') //false 
/(?<=Roger) Waters/.test('Roger is my dog and Roger Waters is a famous musician') //true

Обзор отрицается использованием ?&lт;!:

/(?<!Roger) Waters/ 
/(?<!Roger) Waters/.test('Pink Waters is my dog') //true 
/(?<!Roger) Waters/.test('Roger is my dog and Roger Waters is a famous musician') //false

Регулярные выражения и Unicode

The u флаг обязателен при работе со строками Unicode. В частности, это касается случаев, когда вам может потребоваться обрабатывать символы в астральных планах (не входящие в первые 1600 символов Unicode).

Смайлики – хороший пример, но они не единственные.

Если вы не добавите этот флажок, это простое регулярное выражение, которое должно соответствовать одному символу, не будет работать, потому что для JavaScript этот смайлик внутри представлен 2 символами (см. Unicode в JavaScript):

/^.$/.test('a') //✅ /^.$/.test('?') //❌ /^.$/u.test('?') //✅  

So, always use the u флаг.

Unicode, just like normal characters, handle ranges:

/[a-z]/.test('a') //✅ /[1-9]/.test('1') //✅ /[?-?]/u.test('?') //✅ /[?-?]/u.test('?') //❌  

JavaScript checks the internal code representation, so ? < ? < ? because \u1F436 < \u1F43A <; &F98A. Проверьте полный список смайлов, чтобы получить эти коды и узнать порядок.

Unicode property escapes

As we saw above, in a regular expression pattern you can use \d соответствовать любой цифре, \s чтобы соответствовать любому символу, не являющемуся пробелом, \w соответствие любому буквенно-цифровому символу и т.п.

The Unicode property escapes is an ES2018 feature that introduces a very cool feature, extending this concept to all Unicode characters introducing \p{} и его возражение \P{}.

Any Unicode character has a set of properties. For example Script определяет языковую семью, ASCII является логическим значением, верным для символов ASCII и т.д. Вы можете поместить это свойство в скобки графика, и регулярное выражение проверит, соответствует ли это действительности:

/^\p{ASCII}+$/u.test('abc') //✅ /^\p{ASCII}+$/u.test('ABC@') //✅ /^\p{ASCII}+$/u.test('ABC?') //❌ 

ASCII_Hex_Digit является еще одним логическим свойством, которое проверяет, содержит ли строку только действительные шестнадцатеричные цифры:

/^\p{ASCII_Hex_Digit}+$/u.test('0123456789ABCDEF') //✅ /^\p{ASCII_Hex_Digit}+$/u.test('h') //❌

There are many other boolean properties, which you just check by adding their name in the graph parentheses, including Uppercase, Lowercase, White_Space, Alphabetic, Emoji и более:

/^\p{Lowercase}$/u.test('h') //✅ /^\p{Uppercase}$/u.test('H') //✅ 
/^\p{Emoji}+$/u.test('H') //❌ /^\p{Emoji}+$/u.test('??') //✅  

In addition to those binary properties, you can check any of the unicode character properties to match a specific value. In this example, I check if the string is written in the Greek or Latin alphabet:

/^\p{Script=Greek}+$/u.test('ελληνικά') //✅ /^\p{Script=Latin}+$/u.test('hey') //✅

Read more about all the properties you can use directly on the proposal.

Examples

Supposing a string has only one number you need to extract, /\d+/ должен это сделать:

'Test 123123329'.match(/\d+/) // Array [ "123123329" ]

Match an email address

A simplistic approach is to check non-space characters before and after the @ подписать, используя \S:

/(\S+)@(\S+)\.(\S+)/ 
/(\S+)@(\S+)\.(\S+)/.exec('copesc@gmail.com') //["copesc@gmail.com", "copesc", "gmail", "com"]

This is a simplistic example, however, as many invalid emails are still satisfied by this regex.

Capture text between double quotes

Suppose you have a string that contains something in double quotes, and you want to extract that content.

The best way to do so is by using a capturing group, because we know the match starts and ends with "и мы можем легко нацелить его, но мы также хотим удалить эти кавычки из нашего результата.

We’ll find what we need in result[1]:

const hello = 'Hello "nice flower"' const result = /"([^']*)"/.exec(hello) //Array [ "\"nice flower\"", "nice flower" ]

Get the content inside an HTML tag

For example get the content inside a span tag, allowing any number of arguments inside the tag:

/<span\b[^>]*>(.*?)&lt;\/span>/ 
/<span\b[^>]*>(.*?)<\/span>/.exec('test')// null 
/<span\b[^>]*>(.*?)<\/span>/.exec('<span>test</span>') // ["&lt;span>test</span>", "test"] 
/<span\b[^>]*>(.*?)<\/span>/.exec('<span class="x">test</span>') // ["<span class="x">test</span>", "test"]

Interested in learning JavaScript? Get my ebook at jshandbook.com

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

Ваш адрес email не будет опубликован.