如何在 JavaScript 中标记整个正则表达式?

How can I tokenize entire regex in JavaScript?

我正在尝试解析时间字符串并将它们转码为我要调用的对象 time module。它只是一个简单的字典对象,具有完整的时间披露。

问题是我必须匹配由数字和时间单位组成的字符串。目前我正在尝试匹配这个正则表达式:
/^(([1-9][0-9]*)(y|m|w|d|h|min|s))+$/g.

我需要它来产生每一场比赛。所以如果我给它输入这个字符串:12y12m12w12d12h12min12s - 它应该 return 像这样的数组:

[
    '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
]

相反,它 return 只是最后一个单元:

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

我可以使用 regex 来做这件事吗?怎么样?

您不应尝试一次匹配整个输入,因为带有 + 后缀的捕获组确实只会捕获最后一个匹配项。

而是迭代子匹配项。如果你需要整个字符串最终匹配,没有任何中断的字符序列,那么调整你的正则表达式,以便它也匹配单独捕获组中的偏离字符:

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. 数字部分
  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);

捕获组仅捕获 最后 场比赛。

新的 matchAll method 将在 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);

这不会为您提供整体的整个字符串匹配(如果需要,插入数组中),但它会为您提供所有其余部分:

实例:

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,你需要一个循环:

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

实例:

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;
}