Java, UX, HTML, CSS, WEB-design

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

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

Название: Новые функции JavaScript, которые изменят способ написания регулярных выражений . Краткое описание: ⭐ Фараз Кель . Дата публикации: 25.01.2022 . Автор: Алишер Валеев .

Для чего создан сайт Novosti-Nedeli.ru

Данный сайт посвящен новостям мира и мира технологий . Также тут вы найдете руководства по различным девайсам.

Сколько лет сайту?

Возраст составляет 3 года


  • Фараз Кельхини

  • 0 Комментарии

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

  • 11 минут чтения

  • JavaScript, Браузеры

Краткое резюме ↬

Если вы когда-либо выполняли какую-либо сложную обработку текста и манипулирование им в JavaScript, вы оцените новые функции, представленные в ES2018. В этой статье мы подробно рассмотрим, как девятая редакция стандарта улучшает возможности обработки текста в JavaScript.

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

Регулярные выражения были частью языка JavaScript с третьей редакции стандарта ECMAScript, которая была представлена ​​в 1999 году. ECMAScript 2018 (или для краткости ES2018) — это девятая редакция стандарта, которая дополнительно улучшает возможности обработки текста в JavaScript за счет введения четыре новых функции:

  • Утверждения просмотра назад
  • Именованные группы захвата
  • s (dotAll) Флаг
  • Экранирование свойства Unicode

Эти новые функции подробно объясняются в следующих подразделах.

Отладка JavaScript

console.log может многое рассказать вам о вашем приложении, но не может по-настоящему отладить ваш код. Для этого вам понадобится полноценный отладчик JavaScript. Читать статью по теме →

Еще после прыжка! Продолжить чтение ниже ↓

Утверждения просмотра назад

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

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

Есть две версии прогнозных утверждений: положительная и отрицательная. Синтаксис положительного просмотра вперед: (?=...). Например, регулярное выражение /Item(?= 10)/ Спички Item только когда за ним следует с пробелом число 10:

const re = /Item(?= 10)/;

console.log(re.exec('Item'));
// → null

console.log(re.exec('Item5'));
// → null

console.log(re.exec('Item 5'));
// → null

console.log(re.exec('Item 10'));
// → ["Item", index: 0, input: "Item 10", groups: undefined]

Этот код использует exec() метод поиска совпадения в строке. Если совпадение найдено, exec() возвращает массив, первым элементом которого является совпадающая строка. То index свойство массива содержит индекс совпадающей строки, а input содержит всю строку, по которой выполнялся поиск. Наконец, если в регулярном выражении используются именованные группы захвата, они помещаются в groups имущество. В таком случае, groups имеет значение undefined потому что нет именованной группы захвата.

Конструкция для отрицательного просмотра вперед (?!...). Отрицательный просмотр вперед утверждает, что шаблон не следует определенному шаблону. Например, узор /Red(?!head)/ Спички Red только если за ним не последовало head:

const re = /Red(?!head)/;

console.log(re.exec('Redhead'));
// → null

console.log(re.exec('Redberry'));
// → ["Red", index: 0, input: "Redberry", groups: undefined]

console.log(re.exec('Redjay'));
// → ["Red", index: 0, input: "Redjay", groups: undefined]

console.log(re.exec('Red'));
// → ["Red", index: 0, input: "Red", groups: undefined]

ES2018 дополняет упреждающие утверждения, добавляя упреждающие утверждения в JavaScript. Обозначается (?<=...)ретроспективное утверждение позволяет сопоставить шаблон, только если ему предшествует другой шаблон.

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

const re = /(?<=€)d+(.d*)?/;

console.log(re.exec('199'));
// → null

console.log(re.exec('$199'));
// → null

console.log(re.exec('€199'));
// → ["199", undefined, index: 1, input: "€199", groups: undefined]

Примечание: Утверждения просмотра вперед и назад часто называют «обзорами».

Отрицательная версия lookbehind обозначается (?<!...) и позволяет сопоставить шаблон, которому не предшествует шаблон, указанный в ретроспективном просмотре. Например, регулярное выражение /(?<!d{3}) meters/ соответствует слову «метры», если перед ним не стоят три цифры:

const re = /(?<!d{3}) meters/;

console.log(re.exec('10 meters'));
// → [" meters", index: 2, input: "10 meters", groups: undefined]

console.log(re.exec('100 meters'));    
// → null

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

const re = /(?<=d{2})(?<!35) meters/;

console.log(re.exec('35 meters'));
// → null

console.log(re.exec('meters'));
// → null

console.log(re.exec('4 meters'));
// → null

console.log(re.exec('14 meters'));
// → ["meters", index: 2, input: "14 meters", groups: undefined]

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

Именованные группы захвата

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

Следующий код дает пример того, как найти имя файла с помощью .jpg расширение в строке, а затем извлеките имя файла:

const re = /(w+).jpg/;
const str="File name: cat.jpg";
const match = re.exec(str);
const fileName = match[1];

// The second element in the resulting array holds the portion of the string that parentheses matched
console.log(match);
// → ["cat.jpg", "cat", index: 11, input: "File name: cat.jpg", groups: undefined]

console.log(fileName);
// → cat

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

const re = /(d{4})-(d{2})-(d{2})/;
const match = re.exec('2020-03-04');

console.log(match[0]);    // → 2020-03-04
console.log(match[1]);    // → 2020
console.log(match[2]);    // → 03
console.log(match[3]);    // → 04

Решение этой проблемы в ES2018 называется группами захвата, которые используют более выразительный синтаксис в виде (?<name>...):

const re = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
const match = re.exec('2020-03-04');

console.log(match.groups);          // → {year: "2020", month: "03", day: "04"}
console.log(match.groups.year);     // → 2020
console.log(match.groups.month);    // → 03
console.log(match.groups.day);      // → 04

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

Подобная конструкция существует во многих новых и традиционных языках программирования. Python, например, использует (?P<name>) синтаксис именованных групп. Неудивительно, что Perl поддерживает именованные группы с синтаксисом, идентичным JavaScript (JavaScript имитировал синтаксис регулярных выражений из Perl). Java также использует тот же синтаксис, что и Perl.

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

const re = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
const match = re.exec('2020-03-04');

console.log(match[0]);    // → 2020-03-04
console.log(match[1]);    // → 2020
console.log(match[2]);    // → 03
console.log(match[3]);    // → 04

Новый синтаксис также хорошо работает с деструктурирующим присваиванием:

const re = /(?<year>d{4})-(?<month>d{2})-(?<day>d{2})/;
const [match, year, month, day] = re.exec('2020-03-04');

console.log(match);    // → 2020-03-04
console.log(year);     // → 2020
console.log(month);    // → 03
console.log(day);      // → 04

То groups объект создается всегда, даже если в регулярном выражении не существует именованной группы:

const re = /d+/;
const match = re.exec('123');

console.log('groups' in match);    // → true

Если необязательная именованная группа не участвует в матче, groups объект по-прежнему будет иметь свойство для этой именованной группы, но свойство будет иметь значение undefined:

const re = /d+(?<ordinal>st|nd|rd|th)?/;

let match = re.exec('2nd');

console.log('ordinal' in match.groups);    // → true
console.log(match.groups.ordinal);         // → nd

match = re.exec('2');

console.log('ordinal' in match.groups);    // → true
console.log(match.groups.ordinal);         // → undefined

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

console.log(/(ww)1/.test('abab'));    // → true

// if the last two letters are not the same 
// as the first two, the match will fail
console.log(/(ww)1/.test('abcd'));    // → false

Чтобы вызвать именованную группу захвата позже в шаблоне, вы можете использовать /k<name>/ синтаксис. Вот пример:

const re = /b(?<dup>w+)s+k<dup>b/;

const match = re.exec("I'm not lazy, I'm on on energy saving mode");        

console.log(match.index);    // → 18
console.log(match[0]);       // → on on

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

const re = /b(?<dup>w+)s+1b/;

const match = re.exec("I'm not lazy, I'm on on energy saving mode");        

console.log(match.index);    // → 18
console.log(match[0]);       // → on on 

Также можно одновременно использовать нумерованную обратную ссылку и именованную обратную ссылку:

const re = /(?<digit>d):1:k<digit>/;

const match = re.exec('5:5:5');        

console.log(match[0]);    // → 5:5:5

Подобно пронумерованным группам захвата, именованные группы захвата могут быть вставлены в замещающее значение replace() метод. Для этого вам нужно будет использовать $<name> построить. Например:

const str="War & Peace";

console.log(str.replace(/(War) & (Peace)/, '$2 & $1'));    
// → Peace & War

console.log(str.replace(/(?<War>War) & (?<Peace>Peace)/, '$<Peace> & $<War>'));    
// → Peace & War

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

const str="War & Peace";

const result = str.replace(/(?<War>War) & (?<Peace>Peace)/, function(match, group1, group2, offset, string) {
    return group2 + ' & ' + group1;
});

console.log(result);    // → Peace & War

s (dotAll) Флаг

По умолчанию точка (.) метасимвол в шаблоне регулярного выражения соответствует любому символу, за исключением символов разрыва строки, включая перевод строки (n) и возврат каретки (r):

console.log(/./.test('n'));    // → false
console.log(/./.test('r'));    // → false

Несмотря на этот недостаток, разработчики JavaScript по-прежнему могут сопоставлять все символы, используя два противоположных класса сокращенных символов, например [wW]который указывает механизму регулярных выражений сопоставлять символ, который является символом слова (w) или символ, не являющийся словом (W):

console.log(/[wW]/.test('n'));    // → true
console.log(/[wW]/.test('r'));    // → true

ES2018 призван решить эту проблему, представив s (dotAll) флаг. Когда этот флаг установлен, он изменяет поведение точки (.) метасимвол для соответствия символам разрыва строки:

console.log(/./s.test('n'));    // → true
console.log(/./s.test('r'));    // → true

То s флаг может использоваться для каждого регулярного выражения и, таким образом, не нарушает существующие шаблоны, основанные на старом поведении метасимвола точки. Помимо JavaScript, s флаг доступен в ряде других языков, таких как Perl и PHP.

Рекомендуемое чтение: Сокращенный мультфильм Введение в WebAssembly

Экранирование свойств Unicode

Среди новых функций, представленных в ES2015, была поддержка Unicode. Однако классы сокращенных символов по-прежнему не могли сопоставляться с символами Unicode, даже если u был установлен флаг.

Рассмотрим следующий пример:

const str="";

console.log(/d/.test(str));     // → false
console.log(/d/u.test(str));    // → false

считается цифрой, но d может соответствовать только ASCII [0-9]так что test() метод возвращает false. Поскольку изменение поведения классов сокращенных символов нарушило бы существующие шаблоны регулярных выражений, было решено ввести новый тип управляющей последовательности.

В ES2018 экранирует свойство Unicode, обозначаемое p{...}доступны в регулярных выражениях, когда u установлен флаг. Теперь, чтобы сопоставить любой номер Unicode, вы можете просто использовать p{Number}как показано ниже:

const str="";
console.log(/p{Number}/u.test(str));     // → true

И чтобы соответствовать любому буквенному символу Unicode, вы можете использовать p{Alphabetic}:

const str="漢";

console.log(/p{Alphabetic}/u.test(str));     // → true

// the w shorthand cannot match 漢
console.log(/w/u.test(str));    // → false

P{...} это отрицательная версия p{...} и соответствует любому символу, который p{...} не:

console.log(/P{Number}/u.test(''));    // → false
console.log(/P{Number}/u.test('漢'));    // → true

console.log(/P{Alphabetic}/u.test(''));    // → true
console.log(/P{Alphabetic}/u.test('漢'));    // → false

Полный список поддерживаемых свойств доступен в текущем предложении спецификации.

Обратите внимание, что использование неподдерживаемого свойства приводит к SyntaxError:

console.log(/p{undefined}/u.test('漢'));    // → SyntaxError

Таблица совместимости

Настольные браузеры

Хром Fire Fox Сафари Край
Утверждения просмотра назад 62 Икс Икс Икс
Именованные группы захвата 64 Икс 11.1 Икс
s (dotAll) Флаг 62 Икс 11.1 Икс
Экранирование свойств Unicode 64 Икс 11.1 Икс

Мобильные браузеры

ChromeДля Android FirefoxДля Android iOS-сафари Пограничный мобильный Самсунг Интернет Веб-просмотр Android
Утверждения просмотра назад 62 Икс Икс Икс 8.2 62
Именованные группы захвата 64 Икс 11.3 Икс Икс 64
s (dotAll) Флаг 62 Икс 11.3 Икс 8.2 62
Экранирование свойств Unicode 64 Икс 11.3 Икс Икс 64

Node.js

  • 8.3.0 (требует --harmony флаг времени выполнения)
  • 8.10.0 (Поддержка для s (dotAll) флаговые и ретроспективные утверждения)
  • 10.0.0 (полная поддержка)

Подведение итогов

ES2018 продолжает работу предыдущих выпусков ECMAScript, делая регулярные выражения более полезными. Новые функции включают в себя ретроспективное утверждение, именованные группы захвата, s (dotAll), а свойство Unicode экранируется. Утверждение Lookbehind позволяет сопоставить шаблон, только если ему предшествует другой шаблон. Именованные группы захвата используют более выразительный синтаксис по сравнению с обычными группами захвата. То s (dotAll) флаг изменяет поведение точки (.) метасимвол для соответствия символам разрыва строки. Наконец, escape-последовательности свойств Unicode предоставляют новый тип escape-последовательностей в регулярных выражениях.

При построении сложных шаблонов часто полезно использовать тестер регулярных выражений. Хороший тестер предоставляет интерфейс для проверки регулярного выражения на строку и отображает каждый шаг, предпринятый движком, что может быть особенно полезно при попытке понять шаблоны, написанные другими. Он также может обнаруживать синтаксические ошибки, которые могут возникнуть в вашем шаблоне регулярного выражения. Regex101 и RegexBuddy — два популярных тестера регулярных выражений, на которые стоит обратить внимание.

Есть ли у вас другие инструменты, чтобы порекомендовать? Поделитесь ими в комментариях!

Сокрушительная редакция
(дм, ил)




Source: https://smashingmagazine.com

Заключение

Вы ознакомились с статьей — Новые функции JavaScript, которые изменят способ написания регулярных выражений

Пожалуйста оцените статью, и напишите комментарий.

Похожие статьи

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

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

Кнопка «Наверх»