简体   繁体   中英

Finding the nth occurrence of a character in a string in javascript

I am working on a javascript code to find the nth occurrence of a character in a string. Using the indexOf() function we are able to get the first occurrence of the character. Now the challenge is to get the nth occurrence of the character. I was able to get the second third occurrence and so on using the code given below:

function myFunction() {
  var str = "abcdefabcddesadfasddsfsd.";

  var n = str.indexOf("d");
  document.write("First occurence " +n );

  var n1 = str.indexOf("d",parseInt(n+1));
  document.write("Second occurence " +n1 );

  var n2 = str.indexOf("d",parseInt(n1+1));
  document.write("Third occurence " +n2 );

  var n3 = str.indexOf("d",parseInt(n2+1));
  document.write("Fourth occurence " +n3);

  // and so on ...
}

The result is given below

First occurence 3 
Second occurence 9 
Third occurence 10 
Fourth occurence 14 
Fifth occurence 18 
Sixth occurence 19

I would like to generalize the script so that I am able to find the nth occurrence of the character as the above code requires us to repeat the script n times. Let me know if there is a better method or alternative to do the same. It would be nice if we just give the occurrence (at run time) to get the index of that character.

The following are some of my questions:

  • How do we do it in JavaScript?
  • Does any framework provide any functionality to do the same implementation in an easier way or what are the alternate methods to implement the same in other frameworks /languages?
function nth_occurrence (string, char, nth) {
    var first_index = string.indexOf(char);
    var length_up_to_first_index = first_index + 1;

    if (nth == 1) {
        return first_index;
    } else {
        var string_after_first_occurrence = string.slice(length_up_to_first_index);
        var next_occurrence = nth_occurrence(string_after_first_occurrence, char, nth - 1);

        if (next_occurrence === -1) {
            return -1;
        } else {
            return length_up_to_first_index + next_occurrence;  
        }
    }
}

// Returns 16. The index of the third 'c' character.
nth_occurrence('aaaaacabkhjecdddchjke', 'c', 3);
// Returns -1. There is no third 'c' character.
nth_occurrence('aaaaacabkhjecdddhjke', 'c', 3);

You can do it easily by implementing a function using charAt() , like this:

function nth_ocurrence(str, needle, nth) {
  for (i=0;i<str.length;i++) {
    if (str.charAt(i) == needle) {
        if (!--nth) {
           return i;    
        }
    }
  }
  return false;
}

alert( nth_ocurrence('aaaaacabkhjecdddchjke', 'c', 3)  );//alerts 16

Thanks to CQQL for let me know what OP really wanted. I updated a bit my original function to achieve the new behaviour.

indexOf takes a second argument, the character index in the string to begin the search.

function nthChar(string, character, n){
    var count= 0, i=0;
    while(count<n && (i=string.indexOf(character,i)+1)){
        count++;
    }
    if(count== n) return i-1;
    return NaN;
}

var s= 'abcbbasdbgasdnnaabaasdert';

nthChar(s,'a',7);

So a nice way to do this is to extend the string class like so:

(function() {
  String.prototype.nthOccurrenceIndex = function(charToMatch, occurrenceIndex) {
    var char, index, matches, _i, _len;
    matches = 0;
    index = 0;
    for (_i = 0, _len = this.length; _i < _len; _i++) {
      char = this[_i];
      if (char === charToMatch) {
        matches += 1;
        if (matches === occurrenceIndex) {
          return index;
        }
      }
      index += 1;
    }
    return -1;
  };

}).call(this);

The much more concise CoffeeScript version:

String.prototype.nthOccurrenceIndex = (charToMatch, occurrenceIndex)->
  matches = 0
  index = 0

  for char in @
    if char is charToMatch
      matches += 1

      return index if matches is occurrenceIndex

    index += 1

  -1

So now you can do stuff like:

"abcabc".nthOccurrenceIndex('a', 1)
# -> 0

"abcabc".nthOccurrenceIndex('a', 2)
# -> 3

"abcabc".nthOccurrenceIndex('a', 3)
# -> -1

function nthIndexOf(search, n) {
    var myArray = []; 
    for(var i = 0; i < myStr.length; i++) {
        if(myStr.slice(i, i + search.length) === search) {
            myArray.push(i);            
        }
    }   
    return myArray[n - 1];
}

A maybe clearer function. Recursive and copy the mechanism of indexOf :

  • Doesn't cause an error if an incorrect number for nth (ie <= 0). It will return -1 like you can give a negative number (or greater than the length of the string) as fromIndex to indexOf .
  • Can take a fromIndex argument (the same than for indexOf : An integer representing the index at which to start the search; the default value is 0. )

 function indexOfNth (string, char, nth, fromIndex=0) { let indexChar = string.indexOf(char, fromIndex); if (indexChar === -1){ return -1; } else if (nth === 1) { return indexChar; } else { return indexOfNth(string, char, nth-1, indexChar+1); } } let test = 'string for research purpose'; console.log('first s:', indexOfNth(test, 's', 1)); console.log('second s:', indexOfNth(test, 's', 2)); console.log('15th s:', indexOfNth(test, 's', 15)); console.log('first z:', indexOfNth(test, 'z', 1)); console.log('-1th s:', indexOfNth(test, 's', -1)); console.log('first s starting from index=1:', indexOfNth(test, 's', 1, 1)); 

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