Bagaimana cara mendapatkan kejadian ke-n dalam sebuah string?

104

Saya ingin mendapatkan posisi awal 2ndterjadinya ABCdengan seperti ini:

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

Bagaimana Anda melakukannya?

Adam
sumber
Kejadian kedua atau yang terakhir? :)
Ja͢ck
Maaf atas kebingungan Saya tidak mencari indeks terakhir. Saya mencari posisi awal nthterjadinya, dalam hal ini yang kedua.
Adam

Jawaban:

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
sumber
26
Saya sebenarnya tidak suka jawaban ini. Diberikan input panjang tak terbatas, itu tidak perlu membuat larik panjang tak terbatas, dan kemudian membuang sebagian besar darinya. Akan lebih cepat dan lebih efisien hanya dengan menggunakan fromIndexargumen secara iteratifString.indexOf
Alnitak
3
function getPosition(str, m, i) { return str.split(m, i).join(m).length; }
salinan
9
Saya akan lebih baik jika Anda menentukan apa arti setiap parameter.
Selamanya
1
@Foreever Saya baru saja mengimplementasikan fungsi yang ditentukan oleh OP
Denys Séguret
5
Ini akan memberi Anda panjang string jika ada < ikemunculan m. Artinya, getPosition("aaaa","a",5)memberi 4, seperti halnya getPosition("aaaa","a",72)! Saya pikir Anda ingin -1 dalam kasus tersebut. var ret = str.split(m, i).join(m).length; return ret >= str.length ? -1 : ret;Anda mungkin juga ingin menangkap i <= 0denganreturn ret >= str.length || i <= 0 ? -1 : ret;
ruffin
70

Anda juga dapat menggunakan string indexOf tanpa membuat array apa pun.

Parameter kedua adalah indeks untuk mulai mencari kecocokan berikutnya.

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
sumber
Saya suka versi ini karena caching yang panjang dan tidak memperluas prototipe String.
Christophe Roussy
8
menurut jsperf metode ini jauh lebih cepat daripada jawaban yang diterima
boop
Penambahan idapat dibuat kurang membingungkan:var i; for (i = 0; n > 0 && i !== -1; n -= 1) { i = str.indexOf(pat, /* fromIndex */ i ? (i + 1) : i); } return i;
hlfcoding
1
Saya lebih suka yang ini daripada jawaban yang diterima karena ketika saya menguji contoh kedua yang tidak ada jawaban lain mengembalikan panjang string pertama di mana yang ini mengembalikan -1. Suara positif dan terima kasih.
Yohanes
2
Tidak masuk akal bahwa ini bukan fitur bawaan JS.
Sinister Beard
20

Bekerja dari jawaban kennebec, saya membuat fungsi prototipe yang akan mengembalikan -1 jika kemunculan ke-n tidak ditemukan daripada 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
sumber
2
Jangan pernah menggunakan camelCase karena adaptasi fitur yang pada akhirnya dapat secara tidak sengaja ditimpa oleh prototipe ini. Dalam hal ini saya akan merekomendasikan semua huruf kecil dan garis bawah (garis untuk URL): String.prototype.nth_index_of. Bahkan jika Anda merasa nama Anda unik dan cukup gila, dunia akan membuktikan bahwa nama Anda bisa dan akan menjadi lebih gila.
Yohanes
Apalagi saat melakukan prototyping. Tentu, tidak ada mungkin pernah menggunakan yang nama metode tertentu meskipun dengan membiarkan diri Anda untuk melakukan itu Anda membuat kebiasaan buruk. Sebuah berbeda walaupun contoh penting: selalu Data melampirkan ketika melakukan SQL INSERTsebagai mysqli_real_escape_stringtidak tidak melindungi terhadap hacks kutip tunggal. Banyak pengkodean profesional tidak hanya memiliki kebiasaan baik tetapi juga memahami mengapa kebiasaan seperti itu penting. :-)
Yohanes
1
Jangan memperpanjang prototipe string.
4

Karena rekursi selalu menjadi jawabannya.

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
sumber
1
@RenanCoelho The tilde ( ~) adalah operator NOT bitwise di JavaScript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Sébastien
2

Inilah solusi saya, yang hanya mengulangi string sampai nkecocokan ditemukan:

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

Metode ini membuat fungsi yang memanggil indeks kejadian ke-n yang disimpan dalam sebuah 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 
}
Sharon Choe
sumber
Saya tidak berpikir Anda telah mendefinisikan myString dalam kode di atas, dan tidak yakin apakah myStr === myString?
Seth Eden
1

Cara yang lebih singkat dan menurut saya lebih mudah, tanpa membuat string yang tidak perlu.

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

Menggunakan indexOfdan Rekursi :

Pertama, periksa apakah posisi ke-n yang lewat lebih besar dari jumlah total kemunculan substring. Jika lolos, secara rekursif menelusuri setiap indeks hingga indeks ke-n ditemukan.

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

Menggunakan [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 ツ
sumber
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
sumber
-2

Saya bermain-main dengan kode berikut untuk pertanyaan lain di StackOverflow dan berpikir bahwa itu mungkin sesuai untuk di sini. Fungsi printList2 memungkinkan penggunaan regex dan mencantumkan semua kejadian secara berurutan. (printList adalah upaya untuk solusi sebelumnya, tetapi gagal dalam beberapa kasus.)

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