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

Posted

技术标签:

【中文标题】如何使用 JS 正则表达式查找所有不匹配字符的索引?【英文标题】:How to find indexes of all non-matching characters with a JS regex? 【发布时间】:2019-07-25 16:33:29 【问题描述】:

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

这里的问题是,如果我这样写:

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 可能不是最好的方法实现我想要的。

【问题讨论】:

无限循环很容易解释:正则表达式有一个g 修饰符,因此尝试匹配多次出现的模式,但是由于您的模式匹配一​​个空字符串,并且您没有检查条件如果index 等于lastIndex,则正则表达式不能在字符串中前进。使用正则表达式匹配任何非字母数字字符,/[\W_]/g 不能'您只需更改正则表达式以便搜索非字母数字字符:/[^A-Za-z0-9]/ @WiktorStribiżew 感谢您的解释,因为这是我提出问题的原因,因为我不明白为什么会这样。 @RobinZigmond 谢谢你,因为这正是我想要达到的目标! 抱歉@WiktorStribiżew,您可以发表您的评论作为答案,以便我接受吗?它解释了为什么exec 以无限循环结束,并为我的案例带来了一个可行的答案,从而解决了这个问题。谢谢! 【参考方案1】:

原因

无限循环很容易解释:正则表达式有一个g 修饰符,因此尝试匹配多次出现的模式,在上一次成功匹配结束后开始每次匹配尝试,即在lastIndex 之后价值:

exec documentation:

如果您的正则表达式使用“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);

另外,请参阅how to move the lastIndex property value manually。

【讨论】:

【参考方案2】:

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

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 的字符不匹配,因为它们是下划线。

【讨论】:

感谢您的回答,但您的意思是破折号/连字符,而不是下划线吗?

以上是关于如何使用 JS 正则表达式查找所有不匹配字符的索引?的主要内容,如果未能解决你的问题,请参考以下文章

JS中search查找某些内容,正则表达式|查找分隔的任何项

js正则表达式

如何使用正则表达式查找具有特定起始字符串的所有匹配项? [复制]

JS的正则表达式

如何匹配以下字符串,但不包括JS中的单词字符与正则表达式?

js 正则表达式,字符串中如何匹配id的内容?