_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/

Определение регулярных выражения​

Определение регулярного выражения, это создание🏗️ шаблона, на основе которого будет происходить работа со строками. В JavaScript регулярные выражения — это объект, который может быть определён двумя способами.

  • Литерал
  • Конструкция

Определение регулярных выражений с использованием литералов. Для регулярных выражений литералами выступают слеши / ... /, они играют ту же роль, что и скобки ' ... ' при создании🏗️ строк.

let regExp = /шаблон/

Если вы решили создавать🏗️ регулярные выражения при помощи литералов, то стоит учитывать, что такой метод создания🏗️ не допускает динамическое изменение задаваемых значений. Происходит это из-за того, что литералы регулярных выражения вызывают предварительную компиляцию при анализе скрипта. banana$/. Метод .test() вернёт true ✅ только в том случае, если вся строка это banana.

Флаги​

Флаги используются для расширения осуществляемого регулярными выражениями поиска.

  • g — при поиске ищет все совпадения;
  • i — поиск не зависит от регистра [Z-z];
  • m — многострочный режим;
  • s — включает режим dotall, при котором точка . может соответствовать символу перевода строки;
  • y — выполняет поиск начиная с символа, который находится на позиции свойства lastindex текущего регулярного выражения;
  • u — включает поддержку Unicode.

Использование флагов при разных способах создания🏗️ шаблона регулярного выражения

  • Литерал
  • Конструкция
let regExp = /шаблон/флаг // prettier-ignore

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

function learnJavaScript() { let regExp = /banana/i, str = ‘faNana RanaNA BaNanA’ return regExp.test(str) ? ‘Нашёл’ : ‘Нету’ }

Loading…

Попробуйте убрать флаг i из примера.

Итого​

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

Проблемы?​

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

Вопросы​

Для чего нужны регулярные выражения?

  1. Cоздание шаблонов
  2. Манипуляции со строками
  3. Редактирования строк

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

  1. Слеш /
  2. Обратный слеш \
  3. Квадратные скобки []

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

  1. В литеральном
  2. В конструкции
  3. При любом способе динамическое изменение допустимо

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

Ссылки​

  1. Learn JavaScript
  2. MDN Web Docs
  3. JS RegExp

Contributors ✨​

Thanks goes to these wonderful people (emoji key):


IIo3iTiv
📖

Dmitriy Vasilev
💵

Resoner2005
🐛 🎨 🖋

Navernoss
🖋 🐛 🎨

Введение в регулярные выражения в JavaScript | by Victoria Likhanova | NOP::Nuances of Programming

Victoria Likhanova

·

Follow

Published in

·

12 min read

·

May 14, 2020

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

Регулярные выражения — это не просто ещё одна часть языка 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

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

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

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

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

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

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

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

До сих пор мы использовали регулярные выражения из простых шаблонов. \t\r\n\v\f]).

Примеры:

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

Операторы контроля

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

Квантификаторы

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

/* Квантификатор - Значение */
* - 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'))
// falseconsole.log(myPattern.test('bk'))
// trueconsole.log(myPattern.test('bok'))
// true
// + - 1 или более совпадений с предшествующим выражением
const myPattern = /\d+/console.log(myPattern.test('word'))
// falseconsole.log(myPattern.test(13))
// true
// ? - Предшествующее выражение необязательно, совпадений 0 или 1

const myPattern = /foo?bar/console.log(myPattern.test('foobar'))
// trueconsole.log(myPattern.test('fooobar'))
// false
// x{n} - Количество вхождений предшествующего выражения "x" равно "n"
const myPattern = /bo{2}m/console.log(myPattern.test('bom'))
// falseconsole.log(myPattern.test('boom'))
// trueconsole.log(myPattern.test('booom'))
// false
// x{n, } - Количество вхождений предшествующего выражения "x" равно, как минимум, "n"
const myPattern = /do{2,}r/console. 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.'))
// trueconsole.log(myPattern.test('Just a text'))
// false
// (?:x) - "x", значение не запоминается.
const myPattern = /(?:war)/console.log(myPattern.test('warsawwar'))
// trueconsole. log(myPattern.test('arsaw'))
// false

Альтернация

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

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

Примеры:

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

Флаги

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

/* Флаг - Значение */
g – Глобальный поиск, не останавливается после нахождения первого совпадения. " и заканчивается "$" (начало и конец каждой строки).

Примеры:

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

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

Читайте также:

  • Чистый код JavaScript — объекты и классы
  • Хроники нового текстового редактора — от замысла до реализации
  • Двоичное дерево поиска: вставка значения с использованием JavaScript

Читайте нас в телеграмме, vk и Яндекс. Дзен

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

$/;

Совпадение последовательностей пробелов

  • Используйте метапоследовательность \s для соответствия любому символу пробела, включая пробелы, табуляции, новые строки и т. д.
  • Используйте квантификатор + для сопоставления одного или нескольких вхождений предыдущего символа.
  • Добавьте глобальный флаг ( g ), чтобы сопоставить все вхождения шаблона в строке.
 const регулярное выражение = /\s+/g; 

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

  • В зависимости от среды разрывы строк могут быть представлены по-разному.
  • Используйте символ
    \r
    для соответствия возврату каретки, символ \n для соответствия символу новой строки и последовательность \r\n для соответствия возврату каретки, за которым следует перевод строки.
  • Добавьте глобальные ( g ) и многострочные ( m ) флаги для соответствия всем вхождениям шаблона в строке.
 const регулярное выражение = /\r|\n|\r\n/gm; 9((?!(abc|bcd)).)*$/;
// Где 'abc' и 'bcd' - шаблон, который вы хотите исключить 

Текст внутри скобок

  • Используйте символы \( и \) для соответствия открывающей и закрывающей скобкам соответственно.
  • Используйте группу захвата между ними и исключите символ закрывающей скобки.
  • Используйте квантификатор + для соответствия одному или нескольким символам, если необходимо.
  • Добавить глобальный флаг ( г 9(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\ д{4}$/;

    Разбить строку на куски размером n

    • Используйте квантификатор
      . {1,n}
      для соответствия любому символу между 1 и n раз.
    • Добавьте глобальный флаг ( g ), чтобы сопоставить все вхождения шаблона в строке.
     const регулярное выражение = /.{1,2}/g;
    // Где «2» — количество символов в чанке 

    По сценарию Ангелоса Чалариса

    Меня зовут Ангелос Чаларис, инженер-программист JavaScript из Афин, Греция. Лучшие фрагменты из моих приключений в программировании публикуются здесь, чтобы помочь другим научиться программировать.

    Если вы хотите оставаться на связи, подписывайтесь на меня Гитхаб.

    • Шпаргалки

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

      Коллекция · 15 фрагментов

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

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

      JavaScript, String · 12 июня 2021 г.

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

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

      JavaScript, String · 12 июня 2021 г.

    • Escape RegExp

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

      JavaScript, String · 15 сентября 2020 г.

    Регулярные выражения — Scala.js

    Регулярные выражения JavaScript отличаются от регулярных выражений Java. Для java.util.regex.Pattern (и его производных, таких как scala.util.matching.Regex и метод .r ) Scala.js реализует семантику регулярных выражений Java, хотя и с некоторыми ограничениями. Семантика и набор функций регулярных выражений JavaScript доступны через js.

    RegExp , как и любой другой API JavaScript.

    Поддержка

    Набор поддерживаемых функций для Pattern зависит от целевой версии ECMAScript, указанной в ESFeatures.esVersion . По умолчанию Scala.js нацелен на ECMAScript 2015. Эту цель можно изменить с помощью следующей настройки:

     scalaJSLinkerConfig ~= (_.withESFeatures(_.withESVersion(ESVersion.ES2018))) 

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

    В частности, мы рекомендуем избегать флага MULTILINE , также известного как (?m) , для которого требуется ES2018. Ниже мы дадим несколько советов, как этого избежать.

    Не поддерживается

    Следующие функции никогда не поддерживаются:

    • флаг CANON_EQ ,
    • \X , \b{g} и \N{...} выражений,
    • \p{In𝘯𝘢𝘮𝘦} классов символов, представляющих
      блоков Unicode
      ,
    • сопоставление границ \G , , кроме , если оно появляется в самом начале регулярного выражения (например, \Gfoo ),
    • встроенных флаговых выражений с внутренними группами, то есть конструкции вида (?idmsuxU-idmsuxU:𝑋) ,
    • выражений встроенных флагов без внутренних групп, т. е. конструкций вида (?idmsuxU-idmsuxU) , за исключением , если они появляются в самом начале регулярного выражения (например, (?i)abc принимается, а ab(?i)c — нет), а
    • числовых «обратных» ссылок на группы, которые определены позже в шаблоне (обратите внимание, что даже Java не поддерживает
      именованных
      обратных ссылок, подобных этому).

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

    Следующие функции требуют esVersion >= ESVersion.ES2015 (по умолчанию верно):

    • флаг UNICODE_CASE .

    Следующие функции требуют esVersion >= ESVersion.ES2018 (по умолчанию false):

    • флаги MULTILINE и UNICODE_CHARACTER_CLASS ,
    • ретроспективных утверждений (?<=𝑋) и (? ,
    • выражения \b и \B , используемые вместе с флагом UNICODE_CASE ,
    • \p{𝘯𝘢𝘮𝘦} выражений, где 𝘯𝘢𝘮𝘦 не является одним из классов символов POSIX.

    Поддерживается всегда

    Стоит отметить, что, помимо прочего, следующие функции поддерживаются во всех случаях, даже если в ECMAScript вообще нет эквивалентной функции или в целевой версии ECMAScript:

    • правильная обработка суррогатных пар (изначально поддерживается в ES 2015+),
    • граничный сопоставитель \G , когда он находится в начале шаблона (соответствует флагу «y», изначально поддерживается в ES 2015+),
    • именованных групп и именованных обратных ссылок (изначально поддерживается в ES 2018+),
    • флаг DOTALL (изначально поддерживается в ES 2018+),
    • Сопоставление без учета регистра ASCII ( CASE_INSENSITIVE включено, но UNICODE_CASE выключено),
    • комментариев с флагом COMMENTS ,
    • Классы символов POSIX в режиме ASCII или их вариант Unicode с UNICODE_CHARACTER_CLASS (если последний сам поддерживается, см. выше), 9г-р]] ),
    • атомных групп (?>𝑋) ,
    • притяжательные квантификаторы 𝑋*+ , 𝑋++ и 𝑋?+ ,
    • \A , \Z и \z граничные согласователи,
    • выражение \R ,
    • встроенные цитаты с \Q и \E , как вне, так и внутри классов символов.

    Все поддерживаемые функции имеют правильную семантику из Java. Это верно даже для функций, существующих в JavaScript, но с другой семантикой, среди которых: 9 и $ граничные сопоставители с флагом MULTILINE (при поддержке последнего),

  • предопределенные классы символов \h , \s , \v , \w и их инвертированные варианты с учетом флага UNICODE_CHARACTER_CLASS ,
  • сопоставление границ \b и \B с учетом флага UNICODE_CHARACTER_CLASS ,
  • внутренний формат \p{𝘯𝘢𝘮𝘦} классов символов, включая \p{java𝘔𝘦𝘵𝘩𝘰𝘥𝘕𝘢𝘮𝘦} классов,
  • восьмеричных побегов и управляющих побегов.

Гарантии

Если функция не поддерживается, во время Pattern.compile() выдается исключение PatternSyntaxException .

Если Pattern.compile() выполняется успешно, регулярное выражение гарантированно будет вести себя точно так же, как на JVM, за исключением для захвата групп в повторяющихся сегментах (как для их обратных ссылок, так и для последующих вызовов group , start и end ):

  • на JVM группа захвата всегда фиксирует любую подстроку, которая была успешно сопоставлена ​​последней этой группой во время обработки регулярного выражения:
    • , даже если это было в предыдущей итерации повторяющегося сегмента, и последняя итерация не имела совпадения для этой группы, или
    • , если это было во время более поздней итерации повторяющегося сегмента, для которого впоследствии был выполнен возврат;
  • в JS и, следовательно, в Scala. js, захват групп в повторяющихся сегментах всегда захватывает то, что было сопоставлено (или нет) во время последней итерации, что в конечном итоге было сохранено.

Поведение JavaScript более «функционально», тогда как поведение JVM более «императивно». Эта императивная природа также отражена в методах hitEnd() и requireEnd() Matcher , которые не поддерживаются (они не связываются).

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

  • JDK-8027747
  • ДДК-8187083
  • ДДК-8187080
  • ЖДК-8187082

Scala.js сохраняет поведение JavaScript и не пытается воспроизвести поведение JVM (что может привести к большим затратам).

Как избежать флага

MULTILINE , также известного как (?m)

Флаг «m» в регулярном выражении JavaScript немного отличается от флага шаблона Java . Он считает, что позиция в середине \r\n последовательность является и началом, и концом строки, тогда как Pattern считает, что ни то, ни другое неверно. Семантика Pattern соответствует рекомендациям Unicode.

Как правило, мы не можем реализовать поведение Pattern без проверок назад ( (?<=𝑋) ), которые доступны только в ECMAScript 2018+. Однако в большинстве конкретных случаев можно заменить использование флага «m» комбинацией а) более сложных шаблонов и б) некоторой специальной логики в коде с использованием регулярного выражения. 9|\n)(foo|bar|)(?=\n|$)""".r

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

 for (m <- regex2.