Làm thế nào để nhận được sự xuất hiện thứ n trong một chuỗi?


104

Tôi muốn có được vị trí bắt đầu của sự 2ndxuất hiện ABCvới một cái gì đó như sau:

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

Bạn sẽ làm điều này như thế nào?


Lần xuất hiện thứ hai hay lần cuối cùng? :)
Ja͢ck

Xin lỗi vì nhầm lẫn, tôi không tìm chỉ mục cuối cùng. Tôi đang tìm vị trí nthxuất hiện bắt đầu , trong trường hợp này là vị trí thứ hai.
Adam

Câu trả lời:


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
Tôi thực sự không thích câu trả lời này. Với đầu vào độ dài không giới hạn, nó không cần thiết phải tạo một mảng độ dài không giới hạn, và sau đó loại bỏ hầu hết nó. Nó sẽ là nhanh hơn và hiệu quả chỉ để lặp đi lặp lại sử dụng các fromIndexlập luận đểString.indexOf
Alnitak

3
function getPosition(str, m, i) { return str.split(m, i).join(m).length; }
sao chép

9
Tôi sẽ rất tốt nếu bạn chỉ định ý nghĩa của từng tham số.
Báo trước

1
@Foreever Tôi chỉ đơn giản là thực hiện chức năng xác định bởi OP
Denys SEGURET

5
Điều này sẽ cung cấp cho bạn độ dài của chuỗi nếu có < ilần xuất hiện của m. Đó là, getPosition("aaaa","a",5)cho 4, như không getPosition("aaaa","a",72)! Tôi nghĩ bạn muốn -1 trong những trường hợp đó. var ret = str.split(m, i).join(m).length; return ret >= str.length ? -1 : ret;Bạn cũng có thể muốn bắt i <= 0vớireturn ret >= str.length || i <= 0 ? -1 : ret;
Ruffin

70

Bạn cũng có thể sử dụng chuỗi indexOf mà không cần tạo bất kỳ mảng nào.

Tham số thứ hai là chỉ số để bắt đầu tìm kiếm trận đấu tiếp theo.

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

Tôi thích phiên bản này vì bộ nhớ đệm chiều dài và không mở rộng nguyên mẫu Chuỗi.
Christophe Roussy

8
theo jsperf phương pháp này là cách nhanh hơn so với câu trả lời được chấp nhận
Boop

Sự gia tăng của icó thể được làm cho ít khó hiểu hơn:var i; for (i = 0; n > 0 && i !== -1; n -= 1) { i = str.indexOf(pat, /* fromIndex */ i ? (i + 1) : i); } return i;
hlfcoding

1
Tôi thích câu này hơn câu trả lời được chấp nhận vì khi tôi kiểm tra trường hợp thứ hai không tồn tại câu trả lời khác trả về độ dài của chuỗi đầu tiên trong đó câu này trả về -1. Một phiếu bầu và cảm ơn bạn.
John

2
Thật vô lý khi đây không phải là một tính năng được tích hợp sẵn của JS.
Sinister Beard

20

Dựa trên câu trả lời của kennebec, tôi đã tạo một hàm nguyên mẫu sẽ trả về -1 nếu lần xuất hiện thứ n không được tìm thấy thay vì 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
Đừng bao giờ sử dụng camelCase vì sự thích ứng cuối cùng của các tính năng có thể vô tình bị ghi đè bởi nguyên mẫu này. Trong trường hợp này tôi khuyên bạn nên tất cả chữ thường và dấu gạch dưới (dấu gạch ngang cho URL): String.prototype.nth_index_of. Ngay cả khi bạn nghĩ rằng tên của bạn là độc nhất và đủ điên rồ, thế giới sẽ chứng minh rằng nó có thể và sẽ còn điên rồ hơn.
John

Đặc biệt là khi làm nguyên mẫu. Chắc chắn, không ai có thể sử dụng tên phương pháp cụ thể mặc dù bằng cách cho phép mình làm điều đó bạn tạo một thói quen xấu. Một ví dụ khác mặc dù quan trọng: luôn bao gồm dữ liệu khi thực hiện một SQL INSERTmysqli_real_escape_stringkhông bảo vệ khỏi các vụ hack trích dẫn đơn lẻ. Phần lớn lập trình viên chuyên nghiệp không chỉ có những thói quen tốt mà còn phải hiểu tại sao những thói quen đó lại quan trọng. :-)
John

1
Không mở rộng nguyên mẫu chuỗi.

4

Bởi vì đệ quy luôn là câu trả lời.

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 Dấu ngã ( ~) là toán tử NOT bitwise trong JavaScript: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Sébastien

2

Đây là giải pháp của tôi, chỉ lặp lại chuỗi cho đến khi ntìm thấy kết quả phù hợp:

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

Phương thức này tạo một hàm gọi chỉ số của lần xuất hiện thứ n được lưu trữ trong một mảng

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 
}

Tôi không nghĩ rằng bạn đã định nghĩa chuỗi myString trong đoạn mã trên và không chắc liệu myStr === myString?
Seth Eden

1

Cách ngắn hơn và tôi nghĩ dễ dàng hơn, mà không tạo ra các chuỗi không cần thiết.

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

Sử dụng indexOfđệ quy :

Đầu tiên, hãy kiểm tra xem vị trí thứ n đã qua có lớn hơn tổng số lần xuất hiện của chuỗi con hay không. Nếu được thông qua, đệ quy đi qua từng chỉ mục cho đến khi tìm thấy chỉ mục thứ 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

Sử dụng [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

Tôi đã thử với đoạn mã sau cho một câu hỏi khác trên StackOverflow và nghĩ rằng nó có thể thích hợp cho ở đây. Hàm printList2 cho phép sử dụng một regex và liệt kê tất cả các lần xuất hiện theo thứ tự. (printList là một nỗ lực với một giải pháp trước đó, nhưng nó không thành công trong một số trường hợp.)

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

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.