简体   繁体   中英

How to get the nth occurrence in a string?

I would like to get the starting position of the 2nd occurrence of ABC with something like this:

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

How would you do it?

 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 )

You can also use the string indexOf without creating any arrays.

The second parameter is the index to start looking for the next match.

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
*/

Working off of kennebec's answer, I created a prototype function which will return -1 if the nth occurence is not found rather than 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;
}

Because recursion is always the answer.

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;
        }
    }
}

Here's my solution, which just iterates over the string until n matches have been found:

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

This method creates a function that calls for the index of nth occurrences stored in an array

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 
}

Shorter way and I think easier, without creating unnecessary strings.

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
}

Using indexOf and Recursion :

First check if the nth position passed is greater than the total number of substring occurrences. If passed, recursively go through each index until the nth one is found.

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);
};

Using [String.indexOf][1]

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));

a simple solution just add string, character and 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
      }

    }
   
  }
}

I needed a function that could search from the end of the string too so I wrote this:

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
}

Usage:

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;
}

I was playing around with the following code for another question on StackOverflow and thought that it might be appropriate for here. The function printList2 allows the use of a regex and lists all the occurrences in order. (printList was an attempt at an earlier solution, but it failed in a number of cases.)

 <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>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM