Comment obtenir la nième occurrence dans une chaîne?


104

Je voudrais obtenir la position de départ de l' 2ndoccurrence de ABCavec quelque chose comme ceci:

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

Comment feriez-vous cela?


La deuxième occurrence ou la dernière? :)
Ja͢ck

Désolé pour la confusion Je ne cherche pas le dernier index. Je cherche la position de départ de l' nthoccurrence, dans ce cas la seconde.
Adam

Réponses:


158

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
)


26
Je n'aime pas vraiment cette réponse. Étant donné une entrée de longueur illimitée, il crée inutilement un tableau de longueur illimitée, puis en jette la majeure partie. Il serait plus rapide et plus efficace d'utiliser simplement l' fromIndexargument de manière itérative pourString.indexOf
Alnitak

3
function getPosition(str, m, i) { return str.split(m, i).join(m).length; }
copie du

9
J'aurais été bien si vous spécifiiez ce que signifiait chaque paramètre.
Foreever

1
@Foreever j'ai simplement implémenté la fonction définie par OP
Denys Séguret

5
Cela va vous donner la longueur de la chaîne s'il y a < ioccurrences de m. Autrement dit, getPosition("aaaa","a",5)donne 4, comme fait getPosition("aaaa","a",72)! Je pense que vous voulez -1 dans ces cas. var ret = str.split(m, i).join(m).length; return ret >= str.length ? -1 : ret;Vous voudrez peut-être aussi attraper i <= 0avecreturn ret >= str.length || i <= 0 ? -1 : ret;
ruffin

70

Vous pouvez également utiliser la chaîne indexOf sans créer de tableaux.

Le deuxième paramètre est l'index pour commencer à rechercher la prochaine correspondance.

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

J'aime cette version en raison de la mise en cache de la longueur et de la non extension du prototype String.
Christophe Roussy

8
selon jsperf, cette méthode est bien plus rapide que la réponse acceptée
boop

L'incrémentation de ipeut être rendue moins confuse:var i; for (i = 0; n > 0 && i !== -1; n -= 1) { i = str.indexOf(pat, /* fromIndex */ i ? (i + 1) : i); } return i;
hlfcoding

1
Je préfère celle-ci à la réponse acceptée car lorsque j'ai testé une deuxième instance qui n'existait pas, l'autre réponse a renvoyé la longueur de la première chaîne où celle-ci a renvoyé -1. Un vote positif et merci.
John

2
Il est absurde que ce ne soit pas une fonctionnalité intégrée de JS.
Sinister Beard

20

En partant de la réponse de kennebec, j'ai créé une fonction prototype qui renverra -1 si la nième occurrence n'est pas trouvée plutôt que 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;
}

2
N'utilisez jamais camelCase car l'adaptation éventuelle des fonctionnalités nativement pourrait être involontairement écrasée par ce prototype. Dans ce cas , je vous recommande de minuscules et underscores (tirets pour les URL): String.prototype.nth_index_of. Même si vous pensez que votre nom est unique et assez fou, le monde prouvera qu'il peut et fera plus fou.
John

Surtout que lors du prototypage. Bien sûr, personne ne peut jamais utiliser ce nom de méthode spécifique, mais en vous permettant de le faire, vous créez une mauvaise habitude. Un exemple différent mais critique: toujours inclure les données lors d'un SQL INSERTcar mysqli_real_escape_stringcela ne protège pas contre les hacks de guillemets simples. Une grande partie du codage professionnel ne consiste pas seulement à avoir de bonnes habitudes, mais aussi à comprendre pourquoi de telles habitudes sont importantes. :-)
John

1
N'étendez pas le prototype de chaîne.

4

Parce que la récursivité est toujours la réponse.

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

1
@RenanCoelho Le tilde ( ~) est l'opérateur NOT au niveau du bit en JavaScript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Sébastien

2

Voici ma solution, qui itère simplement sur la chaîne jusqu'à ce que des ncorrespondances aient été trouvées:

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

2

Cette méthode crée une fonction qui appelle l'index des nièmes occurrences stockées dans un tableau

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 
}

Je ne pense pas que vous ayez défini myString dans le code ci-dessus, et je ne sais pas si myStr === myString?
Seth Eden le

1

Chemin plus court et je pense plus facile, sans créer de chaînes inutiles.

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
}

0

Utilisation indexOfet récursivité :

Vérifiez d'abord si la nième position passée est supérieure au nombre total d'occurrences de sous-chaîne. S'il est passé, parcourez récursivement chaque index jusqu'à ce que le nième soit trouvé.

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

0

En utilisant [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

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

-2

Je jouais avec le code suivant pour une autre question sur StackOverflow et j'ai pensé que cela pourrait être approprié pour ici. La fonction printList2 permet l'utilisation d'une regex et répertorie toutes les occurrences dans l'ordre. (printList était une tentative de solution antérieure, mais elle a échoué dans un certain nombre de cas.)

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

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.