如何获得字符串中的第 n 个匹配项?

我想得到的起始位置的 2nd发生的 ABC与这样的东西:

var string = "XYZ 123 ABC 456 ABC 789 ABC";
getPosition(string, 'ABC', 2) // --> 16

你会怎么做?

140376 次浏览

const string = "XYZ 123 ABC 456 ABC 789 ABC";


function getPosition(string, subString, index) {
return string.split(subString, index).join(subString).length;
}


console.log(
getPosition(string, 'ABC', 2) // --> 16
)

因为递归永远是答案。

function getPosition(input, search, nth, curr, cnt) {
curr = curr || 0;
cnt = cnt || 0;
var index = input.indexOf(search);
if (curr === nth) {
if (~index) {
return cnt;
}
else {
return -1;
}
}
else {
if (~index) {
return getPosition(input.slice(index + search.length),
search,
nth,
++curr,
cnt + index + search.length);
}
else {
return -1;
}
}
}

下面是我的解决方案,它只是在字符串上迭代,直到找到匹配的 n:

String.prototype.nthIndexOf = function(searchElement, n, fromElement) {
n = n || 0;
fromElement = fromElement || 0;
while (n > 0) {
fromElement = this.indexOf(searchElement, fromElement);
if (fromElement < 0) {
return -1;
}
--n;
++fromElement;
}
return fromElement - 1;
};


var string = "XYZ 123 ABC 456 ABC 789 ABC";
console.log(string.nthIndexOf('ABC', 2));


>> 16

也可以使用字符串 indexOf 而不创建任何数组。

第二个参数是开始寻找下一个匹配的索引。

function nthIndex(str, pat, n){
var L= str.length, i= -1;
while(n-- && i++<L){
i= str.indexOf(pat, i);
if (i < 0) break;
}
return i;
}


var s= "XYZ 123 ABC 456 ABC 789 ABC";


nthIndex(s,'ABC',3)


/*  returned value: (Number)
24
*/

根据 kennebec 的答案,我创建了一个原型函数,如果找不到第 n 个事件,它将返回 -1,而不是0。

String.prototype.nthIndexOf = function(pattern, n) {
var i = -1;


while (n-- && i++ < this.length) {
i = this.indexOf(pattern, i);
if (i < 0) break;
}


return i;
}

此方法创建一个函数,该函数调用存储在数组中的第 n 个匹配项的索引

function nthIndexOf(search, n) {
var myArray = [];
for(var i = 0; i < myString.length; i++) { //loop thru string to check for occurrences
if(myStr.slice(i, i + search.length) === search) { //if match found...
myArray.push(i); //store index of each occurrence
}
}
return myArray[n - 1]; //first occurrence stored in index 0
}

对于 StackOverflow 上的另一个问题,我正在研究下面的代码,并认为它可能适合于这里。PrintList2函数允许使用正则表达式,并按顺序列出所有匹配项。(printList 是对早期解决方案的尝试,但在许多情况下都失败了。)

<html>
<head>
<title>Checking regex</title>
<script>
var string1 = "123xxx5yyy1234ABCxxxabc";
var search1 = /\d+/;
var search2 = /\d/;
var search3 = /abc/;
function printList(search) {
document.writeln("<p>Searching using regex: " + search + " (printList)</p>");
var list = string1.match(search);
if (list == null) {
document.writeln("<p>No matches</p>");
return;
}
// document.writeln("<p>" + list.toString() + "</p>");
// document.writeln("<p>" + typeof(list1) + "</p>");
// document.writeln("<p>" + Array.isArray(list1) + "</p>");
// document.writeln("<p>" + list1 + "</p>");
var count = list.length;
document.writeln("<ul>");
for (i = 0; i < count; i++) {
document.writeln("<li>" +  "  " + list[i] + "   length=" + list[i].length +
" first position=" + string1.indexOf(list[i]) + "</li>");
}
document.writeln("</ul>");
}
function printList2(search) {
document.writeln("<p>Searching using regex: " + search + " (printList2)</p>");
var index = 0;
var partial = string1;
document.writeln("<ol>");
for (j = 0; j < 100; j++) {
var found = partial.match(search);
if (found == null) {
// document.writeln("<p>not found</p>");
break;
}
var size = found[0].length;
var loc = partial.search(search);
var actloc = loc + index;
document.writeln("<li>" + found[0] + "  length=" + size + "  first position=" + actloc);
// document.writeln("  " + partial + "  " + loc);
partial = partial.substring(loc + size);
index = index + loc + size;
document.writeln("</li>");
}
document.writeln("</ol>");


}
</script>
</head>
<body>
<p>Original string is <script>document.writeln(string1);</script></p>
<script>
printList(/\d+/g);
printList2(/\d+/);
printList(/\d/g);
printList2(/\d/);
printList(/abc/g);
printList2(/abc/);
printList(/ABC/gi);
printList2(/ABC/i);
</script>
</body>
</html>

使用 indexOf递归:

首先检查传递的第 n 个位置是否大于子字符串出现的总次数。如果传递,则递归地遍历每个索引,直到找到第 n 个索引。

var getNthPosition = function(str, sub, n) {
if (n > str.split(sub).length - 1) return -1;
var recursePosition = function(n) {
if (n === 0) return str.indexOf(sub);
return str.indexOf(sub, recursePosition(n - 1) + 1);
};
return recursePosition(n);
};

使用 String.indexOf:

var stringToMatch = "XYZ 123 ABC 456 ABC 789 ABC";


function yetAnotherGetNthOccurance(string, seek, occurance) {
var index = 0, i = 1;


while (index !== -1) {
index = string.indexOf(seek, index + 1);
if (occurance === i) {
break;
}
i++;
}
if (index !== -1) {
console.log('Occurance found in ' + index + ' position');
}
else if (index === -1 && i !== occurance) {
console.log('Occurance not found in ' + occurance + ' position');
}
else {
console.log('Occurance not found');
}
}


yetAnotherGetNthOccurance(stringToMatch, 'ABC', 2);
// Output: Occurance found in 16 position


yetAnotherGetNthOccurance(stringToMatch, 'ABC', 20);
// Output: Occurance not found in 20 position


yetAnotherGetNthOccurance(stringToMatch, 'ZAB', 1)
// Output: Occurance not found
function getStringReminder(str, substr, occ) {
let index = str.indexOf(substr);
let preindex = '';
let i = 1;
while (index !== -1) {
preIndex = index;
if (occ == i) {
break;
}
index = str.indexOf(substr, index + 1)
i++;
}
return preIndex;
}
console.log(getStringReminder('bcdefgbcdbcd', 'bcd', 3));

更快捷的方式和我认为更容易,没有创造不必要的字符串。

const findNthOccurence = (string, nth, char) => {
let index = 0
for (let i = 0; i < nth; i += 1) {
if (index !== -1) index = string.indexOf(char, index + 1)
}
return index
}

一个简单的解决方案就是添加字符串、字符和 idx:

function getCharIdx(str,char,n){
let r = 0
for (let i = 0; i<str.length; i++){
if (str[i] === char){
r++
if (r === n){
return i
}


}
   

}
}

我也需要一个能从字符串末尾搜索的函数,所以我写了这个:

function getPos(str, char, index, backwards) {
var split = str.split(char);
var result = 0;
var done = false;


split.forEach(function (item, i) {
if (done) {return}
result += item.length
if (!backwards && i === index) {
done = true
return
} else if (backwards && i === split.length - index - 2) {
done = true
return
}
result += char.length
})
return result
}

用法:

getPos('x x x', 'x', 1, false) // 2
getPos('x x x', 'x', 0, true) // 4
var getPosition = function(string, subStr, index) {
if(!string.includes(subStr)) return null;


let arrs = string.split(subStr);
if(arrs.length < index) return null;


let result = 0;
for (let i = 0; i < index; i++) {
result += arrs[i].length;
}
result += (index - 1) * subStr.length;
return result;
}