如何使用JS正则表达式查找所有不匹配字符的索引?

4

我有一个字符串,我想获得一个数组,其中包含该字符串中不符合特定正则表达式条件的字符的索引(位置)。

问题在于,如果我像这样写:

let match;
let reg = /[A-Za-z]|[0-9]/g;
let str = "1111-253-asdasdas";
let indexes = [];

do {
    match = reg.exec(str);
    if (match) indexes.push(match.index);
} while (match);

它有效。它返回所有数字或字母字符的索引。但问题是,如果我尝试使用正则表达式中的负向前瞻来实现相反的效果,像这样:

let match;
let reg = /(?!([A-Za-z]|[0-9]))/g;
let str = "1111-253-asdasdas";
let indexes = [];

do {
    match = reg.exec(str);
    if (match) indexes.push(match.index);
} while (match);

它最终会陷入无限循环。

我想要实现的目标与第一种情况相同,但是使用否定的正则表达式,因此在这种情况下结果将是:

indexes = [4, 8]; // which are the indexes in which a non-alphanumerical character appears

循环有问题,还是正则表达式搞错了?也许exec在处理负向前瞻的正则表达式时存在问题?我能理解正则表达式不按我预期的方式工作(因为它可能格式不正确),但我不理解无限循环,这让我认为exec可能不是实现我想要的功能的最佳方法。

1
无限循环很容易解释:正则表达式带有 g 修饰符,因此尝试匹配模式的多个出现次数,但由于您的模式匹配空字符串,并且您没有检查 index 是否等于 lastIndex 的条件,所以正则表达式无法在字符串中前进。使用正则表达式匹配任何非字母数字字符,/[\W_]/g - Wiktor Stribiżew
2
你能否只更改正则表达式,使其搜索非字母数字字符:/[^A-Za-z0-9]/ - Robin Zigmond
@WiktorStribiżew 感谢您的解释,这正是我提出问题的原因,因为我不明白为什么会发生这种情况。 - Unapedra
@RobinZigmond谢谢你,因为那正是我想要实现的! - Unapedra
1
抱歉@WiktorStribiżew,您能将您的评论作为答案发布,这样我就可以接受它了吗?它解释了为什么“exec”陷入无限循环,并且还提供了一个适用于我的情况的工作答案,解决了问题。谢谢! - Unapedra
显示剩余2条评论
2个回答

3
这种方法会用星号 * 替换所有匹配的字符。然后,我们迭代那个被替换的字符串,并检索所有不匹配正则表达式字符类的索引。

var str = "1111-253-asdasdas";
var pattern = /[^A-Za-z0-9]/g;
str = str.replace(pattern, "*");

var indices = [];
for(var i=0; i < str.length;i++) {
    if (str[i] === "*") indices.push(i);
}
console.log(indices.toString());

在这种情况下,只有第4和第8个位置的字符不匹配,因为它们是下划线。

1
谢谢您的回答,但是您是指破折号/连字符,而不是下划线吗? - Crashalot

2

原因

无限循环很容易解释:正则表达式使用了g修饰符,因此尝试匹配模式的多个出现次数,并在每次匹配尝试之后从上一次成功匹配的结束位置开始匹配,也就是从lastIndex值之后:

请参阅exec文档

如果你的正则表达式使用了 "g" 标志,则可以使用 exec() 方法在同一个字符串中多次查找连续的匹配项。当这样做时,搜索从由正则表达式的lastIndex属性指定的str子字符串开始。

但是,由于您的模式匹配空字符串,并且您没有检查索引是否等于lastIndex的条件,因此正则表达式无法在字符串中前进。

解决方案

使用正则表达式匹配任何非字母数字字符,/[\W_]/g。由于它不匹配空字符串,RegExp对象的lastIndex属性将在每次匹配时更改,并且不会发生无限循环。

JS演示:

let match, indexes = [];
let reg = /[\W_]/g;
let str = "1111-253-asdasdas";

while (match = reg.exec(str)) {
    indexes.push(match.index);
}
console.log(indexes);

此外,参见如何手动移动lastIndex属性值。最初的回答。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接