Как я могу токенизировать все регулярные выражения в JavaScript? - PullRequest
0 голосов
/ 09 февраля 2020

Я пытаюсь разобрать строки времени и перекодировать их в объект, который я назову time module. Это просто объект словаря с полным раскрытием времени.

Дело в том, что мне нужно сопоставить строку, состоящую из числа и единицы времени. В настоящее время я пытаюсь найти соответствие этому регулярному выражению:
/^(([1-9][0-9]*)(y|m|w|d|h|min|s))+$/g.

Мне нужно, чтобы он выдавал каждое совпадение. Поэтому, если я передаю эту строку: 12y12m12w12d12h12min12s - она ​​должна вернуть что-то вроде этого массива:

[
    '12y12m12w12d12h12min12s',    // Matching string
    '12y',
    '12',
    'y',
    '12m',
    '12',
    'm',
    '12w',
    '12',
    'w',
    '12d',
    '12',
    'd',
    '12h',
    '12',
    'h',
    '12min',
    '12',
    'min',
    '12s',
    '12',
    's',
    index: 0,
    input: '12y12m12w12d12h12min12s',
    groups: undefined
]

Вместо этого она возвращает только последний блок:

[
    '12y12m12w12d12h12min12s',       
    '12s',
    '12',
    's',
    index: 0,
    input: '12y12m12w12d12h12min12s',
    groups: undefined
]

Могу ли я сделать эта вещь, используя regex? Как?

Ответы [ 2 ]

1 голос
/ 09 февраля 2020

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

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

let regex = /([1-9][0-9]*)(y|min|m|w|d|h|s)|(.)/g
let s = "12y12m12w12d12h12min12s";
let matches = [...s.matchAll(regex)];
console.log(matches);

Итак, вывод представляет собой двумерный массив, в котором каждая строка имеет 4 элемента:

  1. полное совпадение одной единицы времени
  2. число c часть
  3. часть единицы
  4. , если это не undefined, то эта строка представляет символ, который не совпадает с шаблоном цифр-единиц

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

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

let regex = /([1-9][0-9]*)(y|min|m|w|d|h|s)|(.)/g
let s = "12y12m12w12d12h12min12s";
let matches = [...s.matchAll(regex)];

if (matches.some(row => row[3])) throw "not matching completely";
matches = matches.flatMap(row => row.slice(0,3));
console.log(matches);
0 голосов
/ 09 февраля 2020

Группы захвата захватывают только последнее совпадение.

Новый matchAll метод из-за ES2020 (и легко заполняемый) делает вас достаточно близко, если вы удалите якоря и выравнивают результат:

const rex = /([1-9][0-9]*)(y|min|m|w|d|h|s)/g;
const str = "12y12m12w12d12h12min12s";
const array = [...str.matchAll(rex)].flat();
console.log(array);

Это не даст вам полное совпадение всей строки (если вы хотите, вставьте в массив), но даст вам все остальное:

Live Пример:

const rex = /([1-9][0-9]*)(y|min|m|w|d|h|s)/g;
const str = "12y12m12w12d12h12min12s";
const array = [...str.matchAll(rex)].flat();
console.log(array);
.as-console-wrapper {
    max-height: 100% !important;
}

Если вы не хотите использовать matchAll, вам понадобится al oop:

const result = [];
let match;
while ((match = rex.exec(str)) !== null) {
    result.push(...match);
}

Live Example :

const rex = /([1-9][0-9]*)(y|min|m|w|d|h|s)/g;
const str = "12y12m12w12d12h12min12s";
const result = [];
let match;
while ((match = rex.exec(str)) !== null) {
    result.push(...match);
}
console.log(result);
.as-console-wrapper {
    max-height: 100% !important;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...