用于匹配零宽度位置的 JS 正则表达式永远循环或根本不匹配

JS regex to match zero-width position either loops forever or doesn't match at all

好的,所以我有这个字符串 "nesˈo:tkʰo:x",我想获取所有 出现在任何实例之后的零宽度位置的索引字符 ˈ(国际音标的主要重音符号)。所以在这种情况下,那些预期的输出将是 0、1、2 和 3 - 出现在 ˈ 的唯一实例之前的字母 nes 的索引,加上 ˈ本身。

我正在使用正则表达式执行此操作,原因我稍后会讲到。 Regex101 确认 /(?=.*?ˈ)/ 应该将所有 4 个零宽度位置与 JS 的正则表达式匹配......但我实际上无法让 JS return 它们。

一个简单的设置可能如下所示:

let teststring = "nesˈo:tkʰo:x";
let re = new RegExp("(?=.*?ˈ)", "g");

while (result = re.exec(teststring)) {
    console.log("Match found at "+result.index);
}

...除了它会永远循环。它似乎卡在了第一场比赛中,据我所知,这与 RegExp.exec 应该如何为全局正则表达式自动递增 RegExp.lastIndex 等有关。但是我也不能使正则表达式 not 全局,或者它不会 return all 像这样的字符串匹配 where预计不止一场比赛。

好的,如果我手动增加 RegExp.lastIndex 以防止它循环呢?

let teststring = "nesˈo:tkʰo:x";
let re = new RegExp("(?=.*?ˈ)", "g");

while (result = re.exec(teststring)) {
    if (result.index == re.lastIndex) {
        re.lastIndex++;
    } else {
        console.log("Match found at "+result.index);
    }
}

现在它...什么都不打印。现在,公平地说,如果 lastIndex 默认情况下从 0 开始,并且第一个匹配项的索引是 0,我有一半希望它被跳过......但为什么它至少不给我 1 , 2 和 3 匹配?

现在,我已经可以听到“你不需要正则表达式,只需执行 Array(teststring.indexOf("ˈ")).keys() 或生成 [0,1,2,3] 的东西”的合唱。这可能适用于这个特定示例,但实际用例是一个解析器函数,它应该是“对于此输入字符串,将 A 的所有实例替换为 B,如果条件 C 为真,除非 条件 D 为真”。这些条件可能类似于“如果 A 在字符串的末尾”或“如果 A 紧挨着 A 的另一个实例”或“如果 A 在 'n' 和 't' 之间”。 那种 种复杂的字符串匹配问题是解析器动态创建和执行正则表达式的原因以及涉及正则表达式的原因,它确实适用于 almost 除了这个烦人的边缘情况之外的所有内容,如果我不需要的话,我宁愿不必重构解析器的整个机制来处理。

使用String.prototype.matchAll()获取所有匹配项。

let teststring = "nesˈo:tkʰo:x";
let re = new RegExp("(?=.*?ˈ)", "g");

[...teststring.matchAll(re)].forEach(result =>
  console.log("Match found at " + result.index)
)

.search() returns 匹配的索引。 .exec() returns 匹配的数组。请注意,不需要提前 (?=),标准捕获组 () 就足够了。

const str =`nesˈo:tkʰo:x",`;
const rgx = /(.*?ˈ)/;

let first = str.search(rgx);
let last = rgx.exec(str)[0].length - 1;

console.log('Indices: '+first+' - '+(first + last)+' \nLength: '+(last+1));