如何使用Javascript获得给定字符串中一组子字符串的第n次出现



我有一个纯字符串

"A <br> B <br/> C <br /> D <br/>" 

以及一组可能的子字符串,如

['<br>','<br/>','<br />'];

在字符串中某个特定字符串的第n次出现的整个字符串中找到索引是微不足道的,所以我可以在第n个'<br>'或第n个'<br/>'的整个字符串上找到索引,但怎么可能找到这些字符串中任何一个的第n个出现呢?

例如,如果我需要2'出现,在这种情况下,它将在9'字符处,也就是说,将第一个<br>计数为第一次出现,将第二个<br/>计数为第二次出现

编辑:查找特定字符串第n次出现的索引可以像这样完成

var index = string.split('<br>', 2).join('<br>').length;

这样我就可以找到不同的事件。问题是要找到这些字符串中任何一个的出现。

您可以尝试使用这样的正则表达式:

let testString="A <br> B <br/> C <br /> D <br/>";
//Array of substrings to be searched for
let testItems=['<br>','<br/>','<br />']; 
//Construction of the regular expression from the given array
let regex=new RegExp(testItems.join("|"),"g"); 
//Getting all matches for the provided regex and reducing it to an array of indices only
let indices=[...testString.matchAll(regex)].map(match=>match.index);
console.log(indices);

第n次出现可以很容易地从索引数组中恢复。如果您需要知道哪个子字符串也被命中,您也可以修改它。

更新

上面的答案没有考虑到搜索项包含正则表达式特殊字符的可能性。要处理这种情况,必须手动转义输入,如下所示。

let testString="A <br> B <br/> C <br /> D <br/> E <br $> F <br []/>";
//Array of substrings to be searched for
let testItems=['<br>','<br/>','<br />','<br $>','<br []/>']; 
//Function to return an escaped version of the input string
let escapeRegex=(string)=> string.replace(/[-/\^$*+?.()|[]{}]/g, '\$&');
//Construction of the regular expression from the given array
let regex=new RegExp(testItems.map(item=>escapeRegex(item)).join("|"),"g");
//Getting all matches for the provided regex and reducing it to an array of indices only
let indices=[...testString.matchAll(regex)].map(match=>match.index);
console.log(indices);

转义输入的函数是从以下问题的答案中借用的:JavaScript中是否有RegExp.escape函数?

感谢@ScottSauyet和@Ivar对的反馈

递归解决方案在这里是有意义的,只要您不希望寻找第10000个匹配或类似的匹配。这里有一种方法:

const indexOfAny = (string, substrings, pos = 0) => {
const positions = substrings .map (ss => string .indexOf (ss, pos)) 
.filter (n => n > -1)
return positions .length == 0 ? -1 : Math .min (... positions)
}
const nthOfAny = (n, string, subtrings, pos = 0) => {
const first = indexOfAny (string, substrings, pos)
return n <= 1
? first
: first == -1
? -1
: nthOfAny (n - 1, string, substrings, 1 + indexOfAny (string, substrings, pos))
}
const string = 'A <br> B <br/> C <br /> D <br/>'
const substrings = ['<br>','<br/>','<br />']
console. log (
nthOfAny (2, string, substrings)
)
console.log (
[1, 2, 3, 4, 5, 6] .map (n => nthOfAny (n, string, substrings))
)

我们首先定义indexOfAny,它接受一个字符串、一个要搜索的子字符串数组和(可选(一个初始位置,它返回第一个找到的位置,如果没有找到,则返回-1

然后,nthOfAny取一个序数(1表示第一个,2表示第二个,等等(和与上面相同的自变量,并通过将pos增加到先前找到的那个并减少n来递归地找到那个,直到它碰到刚好返回indexOfAny的结果的基本情况。

有相当多的额外复杂性意味着使用-1来表示没有找到任何东西,以匹配indexOf。对于这种情况,一个更简单的解决方案将返回Infinity

const indexOfAny = (string, substrings, pos = 0) => 
Math.min (
... substrings .map (ss => string .indexOf (ss, pos)) .filter (n => n > -1)
)
const nthOfAny = (n, string, subtrings, pos = 0) => 
n <= 1
? indexOfAny (string, substrings, pos)
: nthOfAny (n - 1, string, substrings, 1 + indexOfAny (string, substrings, pos))

最新更新