Нулевое базовое изучение регуляризации javascript, от начального уровня до мастерства

внешний интерфейс JavaScript
Нулевое базовое изучение регуляризации javascript, от начального уровня до мастерства

Это второй день моего участия в августовском испытании обновлений, подробности о мероприятии:Испытание августовского обновления

Регулярное расширение

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

В ES5,RegExpЕсть два случая для параметров конструктора.

В первом случае параметр представляет собой строку, а второй параметр представляет собой модификатор (флаг) регулярного выражения.

var regex = new RegExp('xyz', 'i');
// 等价于
var regex = /xyz/i;

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

var regex = new RegExp(/xyz/i);
// 等价于
var regex = /xyz/i;

Однако в настоящее время ES5 не позволяет добавлять модификаторы со вторым параметром, иначе будет сообщено об ошибке.

var regex = new RegExp(/xyz/, 'i');
// Uncaught TypeError: Cannot supply flags when constructing one RegExp from another

ES6 изменил это поведение. еслиRegExpПервый параметр конструктора — это обычный объект, затем вы можете использовать второй параметр для указания модификатора. Кроме того, возвращаемое регулярное выражение игнорирует модификаторы исходного регулярного выражения и использует только новые указанные модификаторы.

new RegExp(/abc/ig, 'i').flags
// "i"

В приведенном выше коде модификатор исходного регулярного объектаig, он будет заменен вторым параметромiпокрытие.

Обычный метод для строк

До ES6 у строковых объектов было 4 метода, которые могли использовать регулярные выражения:match(),replace(),search()а такжеsplit().

ES6 вызывает все эти 4 метода внутри языкаRegExpМетод экземпляра , чтобы все обычные методы были определены вRegExpна объекте.

  • String.prototype.matchпередачаRegExp.prototype[Symbol.match]
  • String.prototype.replaceпередачаRegExp.prototype[Symbol.replace]
  • String.prototype.searchпередачаRegExp.prototype[Symbol.search]
  • String.prototype.splitпередачаRegExp.prototype[Symbol.split]

у модификатор

ES6 добавляет регулярные выраженияuмодификатор, означающий «режим Unicode», используемый для правильной обработки более чем\uFFFFсимволы Юникода. То есть четырехбайтная кодировка UTF-16 обрабатывается правильно.

/^\uD83D/u.test('\uD83D\uDC2A') // false
/^\uD83D/.test('\uD83D\uDC2A') // true

В приведенном выше коде\uD83D\uDC2Aпредставляет собой четырехбайтовую кодировку UTF-16, представляющую один символ. Однако ES5 не поддерживает четырехбайтную кодировку UTF-16 и распознает ее как два символа, в результате чего вторая строка кода приводит кtrue. ДобавленuПосле модификатора ES6 распознает его как символ, поэтому результатом первой строки кода будетfalse.

После добавленияuМодификаторы изменят поведение следующих регулярных выражений.

(1) Точечный символ

точка(.) в регулярном выражении означает любой отдельный символ, кроме символа новой строки. Для кодовых точек больше, чем0xFFFFНеобходимо добавить символы Unicode, символ точки не распознается.uмодификатор.

var s = '𠮷';

/^.$/.test(s) // false
/^.$/u.test(s) // true

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

(2) Представление символов Unicode

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

/\u{61}/.test('a') // false
/\u{61}/u.test('a') // true
/\u{20BB7}/u.test('𠮷') // true

Приведенный выше код означает, что если вы не добавитеuмодификатор, не распознанный регулярным выражением\u{61}Это обозначение считает, что это соответствует только 61 последовательномуu.

(3) Квантификаторы

использоватьuПосле модификатора все кванты будут правильно идентифицировать кодовую точку.0xFFFFсимволы Юникода.

/a{2}/.test('aa') // true
/a{2}/u.test('aa') // true
/𠮷{2}/.test('𠮷𠮷') // false
/𠮷{2}/u.test('𠮷𠮷') // true

(4) Предопределенный режим

uМодификаторы также влияют на предопределенные шаблоны, независимо от того, больше ли кодовых точек, чем0xFFFFсимволы Юникода.

/^\S$/.test('𠮷') // false
/^\S$/u.test('𠮷') // true

код выше\S— это предопределенный шаблон, который соответствует всем символам, не являющимся пробелами. только добавилuмодификатор, который правильно соответствует кодовым точкам больше, чем0xFFFFсимволы Юникода.

Используя это, можно написать функцию, которая правильно возвращает длину строки.

function codePointLength(text) {
  var result = text.match(/[\s\S]/gu);
  return result ? result.length : 0;
}

var s = '𠮷𠮷';

s.length // 4
codePointLength(s) // 2

(5) я модификатор

Некоторые символы Unicode имеют разные кодировки, но очень похожие шрифты, например,\u004Bа также\u212Aвсе в верхнем регистреK.

/[a-z]/i.test('\u212A') // false
/[a-z]/iu.test('\u212A') // true

В приведенном выше коде не добавляйтеuмодификатор, он не распознает неканоническийKперсонаж.

(6) Побег

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

/\,/ // /\,/
/\,/u // 报错

В приведенном выше коде нетuмодификатор, обратная косая черта перед запятой недействительна, добавьтеuМодификатор сообщает об ошибке.

RegExp.prototype.unicode Свойство

Добавлен обычный экземпляр объектаunicodeсвойство, указывающее, установлено ли оноuмодификатор.

const r1 = /hello/;
const r2 = /hello/u;

r1.unicode // false
r2.unicode // true

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

у модификатор

Кромеuмодификаторы, ES6 также добавляет регулярные выраженияyмодификаторы, называемые «липкими» модификаторами.

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

var s = 'aaa_aa_a';
var r1 = /a+/g;
var r2 = /a+/y;

r1.exec(s) // ["aaa"]
r2.exec(s) // ["aaa"]

r1.exec(s) // ["aa"]
r2.exec(s) // null

В приведенном выше коде есть два регулярных выражения, одно из которых используетgмодификатор, другой используетyмодификатор. Каждое из этих двух регулярных выражений выполняется дважды.При первом выполнении оба ведут себя одинаково, а остальные строки_aa_a. из-заgУ украшения нет требований к расположению, поэтому второе выполнение возвращает результат, иyМодификатор требует, чтобы совпадение начиналось с головы, поэтому вернитеnull.

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

var s = 'aaa_aa_a';
var r = /a+_/y;

r.exec(s) // ["aaa_"]
r.exec(s) // ["aa_"]

Каждый приведенный выше код совпадения начинается с заголовка оставшейся строки.

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

const REGEX = /a/g;

// 指定从2号位置(y)开始匹配
REGEX.lastIndex = 2;

// 匹配成功
const match = REGEX.exec('xaya');

// 在3号位置匹配成功
match.index // 3

// 下一次匹配从4号位开始
REGEX.lastIndex // 4

// 4号位开始匹配失败
REGEX.exec('xaya') // null

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

yМодификаторы также подчиняютсяlastIndexсобственность, но требование должно быть вlastIndexСовпадение было найдено в указанном месте.

const REGEX = /a/y;

// 指定从2号位置开始匹配
REGEX.lastIndex = 2;

// 不是粘连,匹配失败
REGEX.exec('xaya') // null

// 指定从3号位置开始匹配
REGEX.lastIndex = 3;

// 3号位置是粘连,匹配成功
const match = REGEX.exec('xaya');
match.index // 3
REGEX.lastIndex // 4

Фактически,yМодификаторы неявно соответствуют флагам в заголовке^.

/b/y.exec('aba')
// null

Поскольку приведенный выше код не может гарантировать совпадение заголовка, он возвращаетnull.yДизайнерский замысел модификатора состоит в том, чтобы голова соответствовала логотипу.^Оба действительны в глобальных матчах.

Ниже находится строковый объектreplaceПримеры методов.

const REGEX = /a/gy;
'aaxa'.replace(REGEX, '-') // '--xa'

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

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

'a1a2a3'.match(/a\d/y) // ["a1"]
'a1a2a3'.match(/a\d/gy) // ["a1", "a2", "a3"]

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

const TOKEN_Y = /\s*(\+|[0-9]+)\s*/y;
const TOKEN_G  = /\s*(\+|[0-9]+)\s*/g;

tokenize(TOKEN_Y, '3 + 4')
// [ '3', '+', '4' ]
tokenize(TOKEN_G, '3 + 4')
// [ '3', '+', '4' ]

function tokenize(TOKEN_REGEX, str) {
  let result = [];
  let match;
  while (match = TOKEN_REGEX.exec(str)) {
    result.push(match[1]);
  }
  return result;
}

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

tokenize(TOKEN_Y, '3x + 4')
// [ '3' ]
tokenize(TOKEN_G, '3x + 4')
// [ '3', '+', '4' ]

В приведенном выше кодеgмодификатор игнорирует недопустимые символы, в то время какyМодификаторы этого не делают, что облегчает обнаружение ошибок.

Свойство RegExp.prototype.sticky

а такжеyМодификаторы совпадают, ES6 имеет более обычные объекты-экземпляры.stickyсвойство, указывающее, установлено ли оноyмодификатор.

var r = /hello\d/y;
r.sticky // true

RegExp.prototype.flags Свойство

ES6 добавляет регулярные выраженияflagsсвойство, которое возвращает модификатор регулярного выражения.

// ES5 的 source 属性
// 返回正则表达式的正文
/abc/ig.source
// "abc"

// ES6 的 flags 属性
// 返回正则表达式的修饰符
/abc/ig.flags
// 'gi'

модификатор s: режим dotAll

В регулярных выражениях точка (.) — это специальный символ, представляющий любой отдельный символ, за двумя исключениями. Один из них представляет собой четырехбайтовый символ UTF-16, который можно использовать сuМодификатор разрешается; другой является символом конца строки.

Так называемый терминатор строки — это символ, обозначающий конец строки. Следующие четыре символа являются «разделителями строк».

  • U+000A Новая строка (\n)
  • U+000D возврат каретки (\r)
  • Разделитель строк U+2028 (разделитель строк)
  • Разделитель абзацев U+2029 (разделитель абзацев)
/foo.bar/.test('foo\nbar')
// false

В приведенном выше коде, потому что.Несоответствие\n, поэтому регулярное выражение возвращаетfalse.

Однако часто нам нужно сопоставить любой отдельный символ, и есть обходной путь.

/foo[^]bar/.test('foo\nbar')
// true

В конце концов, это решение не очень интуитивно понятно, ES2018представлятьsмодификатор такой, что.Может соответствовать любому одиночному символу.

/foo.bar/s.test('foo\nbar') // true

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

const re = /foo.bar/s;
// 另一种写法
// const re = new RegExp('foo.bar', 's');

re.test('foo\nbar') // true
re.dotAll // true
re.flags // 's'

/sМодификаторы и многострочные модификаторы/mНет конфликта, когда они используются вместе,.соответствует всем символам, а^а также$Соответствует началу и концу каждой строки.

ретроспективное утверждение

Регулярные выражения языка JavaScript поддерживают только просмотр вперед и отрицательный просмотр вперед, но не просмотр назад и отрицательный просмотр назад. Представлено в ES2018ретроспективное утверждениеV8 Engine версия 4.9 (Chrome 62) уже поддерживается.

«Первое утверждение» означает, чтоxтолько вyПередняя часть соответствует только и должна быть записана как/x(?=y)/. Например, чтобы соответствовать только цифрам до знака процента, напишите/\d+(?=%)/. «Упреждающее отрицательное утверждение» означает,xтолько отсутствуетyПередняя часть соответствует только и должна быть записана как/x(?!y)/. Например, чтобы соответствовать только номерам, которые не предшествуют знаку процента, напишите/\d+(?!%)/.

/\d+(?=%)/.exec('100% of US presidents have been male')  // ["100"]
/\d+(?!%)/.exec('that’s all 44 of them')                 // ["44"]

Приведенные выше две строки, если вы поменяете регулярные выражения местами, не дадут того же результата. Кроме того, вы также можете видеть, что часть между скобками «прогнозируемого утверждения» ((?=%)), не включается в возвращаемый результат.

Утверждение просмотра назад противоположно утверждению просмотра вперед,xтолько вyсоответствовать только позже, должно быть записано как/(?<=y)x/. Например, чтобы соответствовать только числам после знака доллара, напишите/(?<=\$)\d+/. Отрицательное утверждение просмотра назад противоположно отрицательному утверждению просмотра вперед.xтолько отсутствуетyсоответствовать только позже, должно быть записано как/(?<!y)x/. Например, чтобы соответствовать только числам, которые не стоят после знака доллара, напишите/(?<!\$)\d+/.

/(?<=\$)\d+/.exec('Benjamin Franklin is on the $100 bill')  // ["100"]
/(?<!\$)\d+/.exec('it’s is worth about €90')                // ["90"]

В приведенном выше примере заключенная в квадратные скобки часть «утверждения позади-за» ((?<=\$)), также не включается в возвращаемый результат.

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

const RE_DOLLAR_PREFIX = /(?<=\$)foo/g;
'$foo %foo foo'.replace(RE_DOLLAR_PREFIX, 'bar');
// '$bar %foo foo'

В приведенном выше коде только после знака доллараfooбудет заменен.

Реализация «утверждения просмотра назад» должна сначала соответствовать/(?<=y)x/изx, затем снова налево, совпадаяyчасть.这种“先右后左”的执行顺序,与所有其他正则操作相反,导致了一些不符合预期的行为。

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

/(?<=(\d+)(\d+))$/.exec('1053') // ["", "1", "053"]
/^(\d+)(\d+)$/.exec('1053') // ["1053", "105", "3"]

В приведенном выше коде нам нужно зафиксировать два групповых совпадения. Без «утверждения просмотра назад» первая скобка находится в жадном режиме, а вторая скобка может захватить только один символ, поэтому результат105а также3. В случае «утверждения за строкой», поскольку порядок выполнения справа налево, вторая скобка является жадным режимом, а первая скобка может захватить только один символ, поэтому результат1а также053.

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

/(?<=(o)d\1)r/.exec('hodor')  // null
/(?<=\1d(o))r/.exec('hodor')  // ["r", "o"]

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

Класс свойств Unicode

ES2018 представлятьновый способ написания классов\p{...}а также\P{...}, что позволяет регулярному выражению соответствовать всем символам, соответствующим свойству Unicode.

const regexGreekSymbol = /\p{Script=Greek}/u;
regexGreekSymbol.test('π') // true

В приведенном выше коде\p{Script=Greek}Указывает, что соответствует греческой букве, поэтому соответствуетπуспех.

Классы свойств Unicode задают имена свойств и значения свойств.

\p{UnicodePropertyName=UnicodePropertyValue}

Для некоторых свойств можно указать только имя свойства или указать только значение свойства.

\p{UnicodePropertyName}
\p{UnicodePropertyValue}

\P{…}да\p{…}Обратное соответствие , т. е. совпадение символов, не удовлетворяющих условию.

Обратите внимание, что эти два типа действительны только для Unicode, поэтому обязательно добавляйте их при их использовании.uмодификатор. если не добавитьuмодификаторы, использование регулярных выражений\pа также\PБудет сообщено об ошибке, ECMAScript резервирует эти два класса.

Благодаря разнообразию свойств Юникода этот новый класс очень выразителен.

const regex = /^\p{Decimal_Number}+$/u;
regex.test('𝟏𝟐𝟑𝟜𝟝𝟞𝟩𝟪𝟫𝟬𝟭𝟮𝟯𝟺𝟻𝟼') // true

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

\p{Number}Даже соответствует римским цифрам.

// 匹配所有数字
const regex = /^\p{Number}+$/u;
regex.test('²³¹¼½¾') // true
regex.test('㉛㉜㉝') // true
regex.test('ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ') // true

Ниже приведены некоторые другие примеры.

// 匹配所有空格
\p{White_Space}

// 匹配各种文字的所有字母,等同于 Unicode 版的 \w
[\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]

// 匹配各种文字的所有非字母的字符,等同于 Unicode 版的 \W
[^\p{Alphabetic}\p{Mark}\p{Decimal_Number}\p{Connector_Punctuation}\p{Join_Control}]

// 匹配 Emoji
/\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F/gu

// 匹配所有的箭头字符
const regexArrows = /^\p{Block=Arrows}+$/u;
regexArrows.test('←↑→↓↔↕↖↗↘↙⇏⇐⇑⇒⇓⇔⇕⇖⇗⇘⇙⇧⇩') // true

именованный групповой матч

Введение

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

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;

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

const RE_DATE = /(\d{4})-(\d{2})-(\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj[1]; // 1999
const month = matchObj[2]; // 12
const day = matchObj[3]; // 31

Одна из проблем с сопоставлением групп заключается в том, что значение каждого сопоставления групп не так просто увидеть, и можно использовать только числа (например,matchObj[1]) ссылка, если порядок групп изменен, порядковый номер должен быть изменен при ссылке.

Введено ES2018именованный групповой матч(Именованные группы захвата) позволяет указать имя для каждого совпадения группы, которое легко читается в коде и на него легко ссылаться.

const RE_DATE = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;

const matchObj = RE_DATE.exec('1999-12-31');
const year = matchObj.groups.year; // "1999"
const month = matchObj.groups.month; // "12"
const day = matchObj.groups.day; // "31"

В приведенном выше коде «соответствие именованной группы» заключено в круглые скобки, а «вопросительный знак + угловая скобка + имя группы» добавляется к заголовку шаблона (?<year>), тогда ты можешьexecметод возвращает результатgroupsИмя группы указано в свойстве. При этом числовой порядковый номер (matchObj[1]) остается в силе.

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

Если именованная группа не совпадает, то соответствующаяgroupsСвойства объекта будутundefined.

const RE_OPT_A = /^(?<as>a+)?$/;
const matchObj = RE_OPT_A.exec('');

matchObj.groups.as // undefined
'as' in matchObj.groups // true

В приведенном выше коде именованная группаasсовпадений не найдено, тоmatchObj.groups.asСтоимость свойстваundefined,а такжеasЭта кнопкаgroupsвсегда присутствует.

Разрушение присваивания и подстановки

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

let {groups: {one, two}} = /^(?<one>.*):(?<two>.*)$/u.exec('foo:bar');
one  // foo
two  // bar

При замене строк используйте$<组名>Относится к именованным группам.

let re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/u;

'2015-01-02'.replace(re, '$<day>/$<month>/$<year>')
// '02/01/2015'

В приведенном выше кодеreplaceВторой параметр — это строковый метод, а не регулярное выражение.

replaceВторой параметр метода также может быть функцией, и последовательность параметров функции следующая.

'2015-01-02'.replace(re, (
   matched, // 整个匹配结果 2015-01-02
   capture1, // 第一个组匹配 2015
   capture2, // 第二个组匹配 01
   capture3, // 第三个组匹配 02
   position, // 匹配开始的位置 0
   S, // 原字符串 2015-01-02
   groups // 具名组构成的一个对象 {year, month, day}
 ) => {
 let {day, month, year} = groups;
 return `${day}/${month}/${year}`;
});

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

Цитировать

Если вы хотите сослаться на «совпадение именованной группы» внутри регулярного выражения, вы можете использовать\k<组名>письма.

const RE_TWICE = /^(?<word>[a-z]+)!\k<word>$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false

Числовые ссылки (\1) остается в силе.

const RE_TWICE = /^(?<word>[a-z]+)!\1$/;
RE_TWICE.test('abc!abc') // true
RE_TWICE.test('abc!ab') // false

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

const RE_TWICE = /^(?<word>[a-z]+)!\k<word>!\1$/;
RE_TWICE.test('abc!abc!abc') // true
RE_TWICE.test('abc!abc!ab') // false

Обычный индекс соответствия

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

теперь естьПредложение этапа 3,дляexec()Возвращаемый результат метода плюсindicesАтрибут, по этому атрибуту можно получить начальную и конечную позиции совпадения.

const text = 'zabbcdef';
const re = /ab/;
const result = re.exec(text);

result.index // 1
result.indices // [ [1, 3] ]

В приведенном выше примереexec()метод возвращает результатresult,этоindexатрибут - это весь результат совпадения (ab) исходное положение, а егоindicesСвойство представляет собой массив, а элементы представляют собой массив начальных и конечных позиций каждого совпадения. Поскольку регулярное выражение в этом примере не имеет группового соответствия, поэтомуindicesМассив имеет только один элемент, что указывает на то, что начальная позиция всего совпадения1, конечное положение3.

Обратите внимание, что начальная позиция включается в результат сопоставления, а конечная позиция не включается в результат сопоставления. Например, результат сопоставленияab, являются первой и второй позициями исходной строки соответственно, тогда конечной позицией является третья позиция.

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

const text = 'zabbcdef';
const re = /ab+(cd)/;
const result = re.exec(text);

result.indices // [ [ 1, 6 ], [ 4, 6 ] ]

В приведенном выше примере регулярное выражение содержит групповое совпадение, тогдаindicesМассив атрибутов состоит из двух элементов, первый элемент — это весь результат совпадения (abbcd), второй член — групповое совпадение (cd) начальная и конечная позиции.

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

const text = 'zabbcdef';
const re = /ab+(cd(ef))/;
const result = re.exec(text);

result.indices // [ [1, 8], [4, 8], [6, 8] ]

В приведенном выше примере регулярное выражение содержит два групповых совпадения, поэтомуindicesМассив свойств состоит из трех элементов.

Если регулярное выражение содержит совпадение именованной группы,indicesМассив атрибутов также будет иметьgroupsАтрибуты. Свойство — это объект, из которого можно получить начальную и конечную позиции именованной группы.

const text = 'zabbcdef';
const re = /ab+(?<Z>cd)/;
const result = re.exec(text);

result.indices.groups // { Z: [ 4, 6 ] }

В приведенном выше примереexec()метод возвращает результатindices.groupsСвойство - это объект, который обеспечивает подходящую группуZначальное и конечное положения.

Если групповое сопоставление получить не удалось,indicesСоответствующий член массива атрибутовundefined,indices.groupsСоответствующий член объекта свойства такжеundefined.

const text = 'zabbcdef';
const re = /ab+(?<Z>ce)?/;
const result = re.exec(text);

result.indices[1] // undefined
result.indices.groups['Z'] // undefined

В приведенном выше примере, поскольку групповое сопоставление не удалось, поэтомуindicesмассив атрибутов иindices.groupsЧлены группы, соответствующие объекту атрибута,undefined.

String.prototype.matchAll()

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

var regex = /t(e)(st(\d?))/g;
var string = 'test1test2test3';

var matches = [];
var match;
while (match = regex.exec(string)) {
  matches.push(match);
}

matches
// [
//   ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"],
//   ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"],
//   ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]
// ]

В приведенном выше кодеwhileОбычное сопоставление каждого раунда выполняется в цикле, всего три раунда.

ES2020повысилсяString.prototype.matchAll()метод для получения всех совпадений одновременно. Однако он возвращает итератор, а не массив.

const string = 'test1test2test3';
const regex = /t(e)(st(\d?))/g;

for (const match of string.matchAll(regex)) {
  console.log(match);
}
// ["test1", "e", "st1", "1", index: 0, input: "test1test2test3"]
// ["test2", "e", "st2", "2", index: 5, input: "test1test2test3"]
// ["test3", "e", "st3", "3", index: 10, input: "test1test2test3"]

В приведенном выше коде, посколькуstring.matchAll(regex)Возвращается итератор, поэтому вы можете использоватьfor...ofВыйдите из цикла. Преимущество возврата итератора по сравнению с возвратом массива заключается в том, что если результат сопоставления представляет собой большой массив, итератор более эффективно использует ресурсы.

Преобразование итератора в массив очень просто, используйте...оператор иArray.from()метод подойдет.

// 转为数组的方法一
[...string.matchAll(regex)]

// 转为数组的方法二
Array.from(string.matchAll(regex))