วิธีการรับเหตุการณ์ที่ n ในสตริง?


104

ฉันต้องการรับตำแหน่งเริ่มต้นของการ2ndเกิดขึ้นABCด้วยสิ่งนี้:

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

คุณจะทำอย่างไร?


เหตุการณ์ที่สองหรือครั้งสุดท้าย? :)
Ja͢ck

ขออภัยสำหรับความสับสนฉันไม่ได้มองหาดัชนีสุดท้าย ฉันกำลังมองหาตำแหน่งเริ่มต้นของnthเหตุการณ์ในกรณีนี้คือวินาที
Adam Halasz

คำตอบ:


159

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
)


27
ที่จริงฉันไม่ชอบคำตอบนี้ ด้วยอินพุตความยาวที่ไม่ถูกผูกไว้มันจะสร้างอาร์เรย์ความยาวที่ไม่ถูกผูกไว้โดยไม่จำเป็นจากนั้นจึงโยนส่วนใหญ่ออกไป มันจะเร็วขึ้นและมีประสิทธิภาพมากขึ้นเพียงแค่ใช้fromIndexอาร์กิวเมนต์ซ้ำไปString.indexOf
Alnitak

4
function getPosition(str, m, i) { return str.split(m, i).join(m).length; }
คัดลอก

9
ฉันคงจะดีถ้าคุณระบุความหมายของแต่ละพารามิเตอร์
ก่อน

1
@ ตลอดกาลฉันเพิ่งใช้ฟังก์ชันที่กำหนดโดย OP
Denys Séguret

5
นี้จะทำให้คุณมีความยาวของสตริงหากมี < การเกิดขึ้นของi mนั่นคือgetPosition("aaaa","a",5)ให้4เช่นเดียวกับgetPosition("aaaa","a",72)! ฉันคิดว่าคุณต้องการ -1 ในกรณีเหล่านั้น var ret = str.split(m, i).join(m).length; return ret >= str.length ? -1 : ret;คุณอาจต้องการจับi <= 0ด้วยreturn ret >= str.length || i <= 0 ? -1 : ret;
ruffin

70

คุณยังสามารถใช้สตริง indexOf โดยไม่ต้องสร้างอาร์เรย์ใด ๆ

พารามิเตอร์ที่สองคือดัชนีเพื่อเริ่มค้นหาคู่ต่อไป

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

ฉันชอบเวอร์ชันนี้เนื่องจากมีการแคชความยาวและไม่ได้ขยายต้นแบบสตริง
Christophe Roussy

8
ตามjsperfวิธีนี้เป็นวิธีที่เร็วกว่าคำตอบที่ยอมรับ
boop

การเพิ่มขึ้นของiอาจทำให้เกิดความสับสนน้อยลง:var i; for (i = 0; n > 0 && i !== -1; n -= 1) { i = str.indexOf(pat, /* fromIndex */ i ? (i + 1) : i); } return i;
hlfcoding

1
ฉันชอบคำตอบนี้มากกว่าคำตอบที่ยอมรับเมื่อฉันทดสอบอินสแตนซ์ที่สองซึ่งไม่มีอยู่คำตอบอื่นส่งคืนความยาวของสตริงแรกโดยที่อันนี้ส่งกลับ -1 อัพโหวตและขอบคุณ
ยอห์น

2
เป็นเรื่องไร้สาระที่นี่ไม่ใช่คุณสมบัติในตัวของ JS
Sinister Beard

20

เมื่อใช้คำตอบของ kennebec ฉันได้สร้างฟังก์ชันต้นแบบซึ่งจะคืนค่า -1 หากไม่พบเหตุการณ์ที่ n แทนที่จะเป็น 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
ไม่ เคยใช้ camelCase เนื่องจากในที่สุดการดัดแปลงคุณสมบัติโดยกำเนิดอาจถูกเขียนทับโดยต้นแบบนี้โดยไม่ได้ตั้งใจ ในกรณีนี้ผมอยากแนะนำให้ทุกกรณีที่ต่ำกว่าและขีดล่าง (ขีดกลางสำหรับ String.prototype.nth_index_ofURL): แม้ว่าคุณจะคิดว่าชื่อของคุณไม่เหมือนใครและบ้าพอที่โลกจะพิสูจน์ได้ว่ามันทำได้และจะบ้าคลั่งกว่าเดิม
John

โดยเฉพาะอย่างยิ่งเมื่อทำการสร้างต้นแบบ แน่นอนว่าไม่มีใครเลยที่อาจจะใช้ที่ชื่อวิธีการเฉพาะแม้ว่าโดยการอนุญาตให้ตัวเองที่จะทำสิ่งที่คุณสร้างนิสัยที่ไม่ดี ที่แตกต่างกัน แต่ที่สำคัญตัวอย่างเช่น: เสมอข้อมูลที่แนบเมื่อทำ SQL INSERTเป็นmysqli_real_escape_stringไม่ได้ป้องกันการแฮ็กคำพูดเดียว การเขียนโค้ดแบบมืออาชีพส่วนใหญ่ไม่ใช่แค่การมีนิสัยที่ดี แต่ยังต้องเข้าใจด้วยว่าทำไมนิสัยดังกล่าวจึงมีความสำคัญ :-)
จอห์น

2
อย่าขยายต้นแบบสตริง

4

เพราะการเรียกซ้ำคือคำตอบเสมอ

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 เครื่องหมายตัวหนอน ( ~) เป็นตัวดำเนินการ bitwise NOT ใน JavaScript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Sébastien

3

นี่คือวิธีแก้ปัญหาของฉันซึ่งจะวนซ้ำบนสตริงจนกว่าnจะพบรายการที่ตรงกัน:

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

วิธีนี้สร้างฟังก์ชันที่เรียกใช้ดัชนีของเหตุการณ์ที่ n ที่เก็บไว้ในอาร์เรย์

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 
}

ฉันไม่คิดว่าคุณได้กำหนด myString ในโค้ดด้านบนและไม่แน่ใจว่า myStr === myString?
Seth Eden

1

วิธีที่สั้นกว่าและฉันคิดว่าง่ายกว่าโดยไม่ต้องสร้างสตริงที่ไม่จำเป็น

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

การใช้indexOfและการเรียกซ้ำ :

ขั้นแรกให้ตรวจสอบว่าตำแหน่งที่ n ที่ส่งผ่านมากกว่าจำนวนสตริงย่อยทั้งหมดที่เกิดขึ้นหรือไม่ หากผ่านไปให้วนซ้ำแต่ละดัชนีจนกว่าจะพบดัชนีที่ n

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

การใช้ [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

ฉันกำลังเล่นกับรหัสต่อไปนี้สำหรับคำถามอื่นใน StackOverflow และคิดว่าอาจเหมาะสมสำหรับที่นี่ ฟังก์ชัน printList2 อนุญาตให้ใช้ regex และแสดงรายการเหตุการณ์ทั้งหมดตามลำดับ (printList เป็นความพยายามในการแก้ปัญหาก่อนหน้านี้ แต่ล้มเหลวในหลาย ๆ กรณี)

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.