Wie erhalte ich das n-te Vorkommen in einer Zeichenfolge?

104

Ich möchte mit so etwas die Ausgangsposition des 2ndAuftretens von bekommen ABC:

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

Wie würdest du es machen?

Adam
quelle
Das zweite oder das letzte Vorkommen? :)
Ja͢ck
Entschuldigung für die Verwirrung Ich suche nicht nach dem letzten Index. Ich suche die Ausgangsposition des nthAuftretens, in diesem Fall die zweite.
Adam

Antworten:

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
)

Denys Séguret
quelle
26
Diese Antwort gefällt mir eigentlich nicht. Bei einer Eingabe mit unbegrenzter Länge wird unnötigerweise ein Array mit unbegrenzter Länge erstellt und das meiste davon weggeworfen. Es wäre schneller und effizienter, nur iterativ das fromIndexArgument zu verwendenString.indexOf
Alnitak
3
function getPosition(str, m, i) { return str.split(m, i).join(m).length; }
Kopie
9
Ich wäre gut gewesen, wenn Sie angegeben hätten, was jeder Parameter bedeutet.
foreever
1
@Foreever Ich habe einfach die von OP definierte Funktion implementiert
Denys Séguret
5
Dies gibt Ihnen die Länge der Zeichenfolge an, wenn < iVorkommen von vorhanden sind m. Das heißt, getPosition("aaaa","a",5)gibt 4, wie auch getPosition("aaaa","a",72)! Ich denke, Sie wollen in diesen Fällen -1. var ret = str.split(m, i).join(m).length; return ret >= str.length ? -1 : ret;Vielleicht möchten Sie auch i <= 0mitreturn ret >= str.length || i <= 0 ? -1 : ret;
Ruffin
70

Sie können den String indexOf auch verwenden, ohne Arrays zu erstellen.

Der zweite Parameter ist der Index, mit dem nach der nächsten Übereinstimmung gesucht werden soll.

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
quelle
Ich mag diese Version, weil die Länge zwischengespeichert wird und der String-Prototyp nicht erweitert wird.
Christophe Roussy
8
Laut jsperf ist diese Methode viel schneller als die akzeptierte Antwort
boop
Das Inkrementieren von ikann weniger verwirrend gemacht werden:var i; for (i = 0; n > 0 && i !== -1; n -= 1) { i = str.indexOf(pat, /* fromIndex */ i ? (i + 1) : i); } return i;
hlfcoding
1
Ich ziehe diese der akzeptierten Antwort vor, da beim Testen auf eine zweite Instanz, die nicht vorhanden war, die andere Antwort die Länge der ersten Zeichenfolge zurückgab, wobei diese -1 -1 zurückgab. Eine Abstimmung und danke.
John
2
Es ist absurd, dass dies keine integrierte Funktion von JS ist.
Bart
20

Ausgehend von Kennebecs Antwort habe ich eine Prototypfunktion erstellt, die -1 zurückgibt, wenn das n-te Vorkommen nicht gefunden wird, sondern 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;
}
ilovett
quelle
2
Verwenden Sie camelCase niemals , da die eventuelle Anpassung von Funktionen von diesem Prototyp unbeabsichtigt überschrieben werden könnte. In diesem Fall würde ich alle Kleinbuchstaben und Unterstriche (Bindestriche für URLs) empfehlen : String.prototype.nth_index_of. Selbst wenn Sie denken, Ihr Name sei einzigartig und verrückt genug, wird die Welt beweisen, dass er verrückter sein kann und wird.
John
Besonders das beim Prototyping. Sicher, niemand darf jemals diesen bestimmten Methodennamen verwenden, wenn Sie sich erlauben, dies zu tun, schaffen Sie eine schlechte Angewohnheit. Ein anderes, wenn auch kritisches Beispiel: Schließen Sie bei einer SQL-Ausführung immer Daten ein, INSERTda mysqli_real_escape_stringdies nicht vor Hacks in einfachen Anführungszeichen schützt. Ein Großteil der professionellen Codierung besteht nicht nur darin, gute Gewohnheiten zu haben, sondern auch zu verstehen, warum solche Gewohnheiten wichtig sind. :-)
John
1
Erweitern Sie den String-Prototyp nicht.
4

Weil Rekursion immer die Antwort ist.

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;
        }
    }
}
Florian Margaine
quelle
1
@ RenanCoelho Die Tilde ( ~) ist der bitweise NICHT-Operator in JavaScript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Sébastien
2

Hier ist meine Lösung, die nur über die Zeichenfolge iteriert, bis nÜbereinstimmungen gefunden wurden:

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
Alnitak
quelle
2

Diese Methode erstellt eine Funktion, die den Index der in einem Array gespeicherten n-ten Vorkommen aufruft

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 
}
Sharon Choe
quelle
Ich glaube nicht, dass Sie myString im obigen Code definiert haben und nicht sicher sind, ob myStr === myString?
Seth Eden
1

Kürzere Art und ich denke einfacher, ohne unnötige Zeichenfolgen zu erstellen.

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
}
Piotr
quelle
0

Verwendung indexOfund Rekursion :

Überprüfen Sie zunächst, ob die n-te übergebene Position größer ist als die Gesamtzahl der Teilzeichenfolgenvorkommen. Wenn bestanden, durchlaufen Sie rekursiv jeden Index, bis der n-te gefunden ist.

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);
};
Eric Amshukov
quelle
0

Verwenden von [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
sk8terboi87 ツ
quelle
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));
Arul Benito
quelle
-2

Ich habe mit dem folgenden Code für eine weitere Frage zu StackOverflow herumgespielt und dachte, dass dies hier angemessen sein könnte. Die Funktion printList2 ermöglicht die Verwendung eines regulären Ausdrucks und listet alle Vorkommen der Reihe nach auf. (printList war ein Versuch einer früheren Lösung, der jedoch in einigen Fällen fehlschlug.)

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

Bradley Ross
quelle