Получить индекс n-го вхождения строки?

Если мне не хватает очевидного встроенного метода, каков самый быстрый способ получить n- е вхождение строки внутри строки?

Я понимаю, что я мог бы закодировать метод IndexOf , обновив свой индекс начала на каждой итерации цикла. Но делать это так кажется мне расточительным.

Это в основном то, что вам нужно сделать – или, по крайней мере, это самое простое решение. Все, что вы «тратите впустую», это стоимость n вызовов метода – вы не будете проверять каждый случай дважды, если вы думаете об этом. (IndexOf вернется, как только он найдет совпадение, и вы продолжите движение от того места, где оно остановилось.)

Вы действительно можете использовать регулярное выражение /((s).*?){n}/ для поиска n-го вхождения подстроки s .

В C # это может выглядеть так:

 public static class StringExtender { public static int NthIndexOf(this string target, string value, int n) { Match m = Regex.Match(target, "((" + Regex.Escape(value) + ").*?){" + n + "}"); if (m.Success) return m.Groups[2].Captures[n - 1].Index; else return -1; } } 

Примечание. Я добавил Regex.Escape в исходное решение, чтобы разрешить поиск символов, имеющих особое значение для двигателя регулярных выражений.

Это в основном то, что вам нужно сделать – или, по крайней мере, это самое простое решение. Все, что вы «тратите впустую», это стоимость n вызовов метода – вы не будете проверять каждый случай дважды, если вы думаете об этом. (IndexOf вернется, как только он найдет совпадение, и вы продолжите движение от того места, где оно остановилось.)

Вот рекурсивная реализация (вышеприведенной идеи ) в качестве метода расширения, искажающая формат метода (ов) структуры:

 public static int IndexOfNth(this string input, string value, int startIndex, int nth) { if (nth < 1) throw new NotSupportedException("Param 'nth' must be greater than 0!"); if (nth == 1) return input.IndexOf(value, startIndex); var idx = input.IndexOf(value, startIndex); if (idx == -1) return -1; return input.IndexOfNth(value, idx + 1, --nth); } 

Кроме того, вот некоторые (MBUnit) модульные тесты, которые могут вам помочь (чтобы доказать, что это правильно):

 using System; using MbUnit.Framework; namespace IndexOfNthTest { [TestFixture] public class Tests { //has 4 instances of the private const string Input = "TestTest"; private const string Token = "Test"; /* Test for 0th index */ [Test] public void TestZero() { Assert.Throws( () => Input.IndexOfNth(Token, 0, 0)); } /* Test the two standard cases (1st and 2nd) */ [Test] public void TestFirst() { Assert.AreEqual(0, Input.IndexOfNth("Test", 0, 1)); } [Test] public void TestSecond() { Assert.AreEqual(4, Input.IndexOfNth("Test", 0, 2)); } /* Test the 'out of bounds' case */ [Test] public void TestThird() { Assert.AreEqual(-1, Input.IndexOfNth("Test", 0, 3)); } /* Test the offset case (in and out of bounds) */ [Test] public void TestFirstWithOneOffset() { Assert.AreEqual(4, Input.IndexOfNth("Test", 4, 1)); } [Test] public void TestFirstWithTwoOffsets() { Assert.AreEqual(-1, Input.IndexOfNth("Test", 8, 1)); } } } 
 private int IndexOfOccurence(string s, string match, int occurence) { int i = 1; int index = 0; while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1) { if (i == occurence) return index; i++; } return -1; } 

или в C # с методами расширения

 public static int IndexOfOccurence(this string s, string match, int occurence) { int i = 1; int index = 0; while (i <= occurence && (index = s.IndexOf(match, index + 1)) != -1) { if (i == occurence) return index; i++; } return -1; } 

Может быть, было бы неплохо работать с String.Split() и проверить, есть ли запрошенное вхождение в массиве, если вам не нужен индекс, но значение в индексе

После некоторого бенчмаркинга это, кажется, самое простое и эффективное решение

 public static int IndexOfNthSB(string input, char value, int startIndex, int nth) { if (nth < 1) throw new NotSupportedException("Param 'nth' must be greater than 0!"); var nResult = 0; for (int i = startIndex; i < input.Length; i++) { if (input[i] == value) nResult++; if (nResult == nth) return i; } return -1; } 

System.ValueTuple ftw:

var index = line.Select((x, i) => (x, i)).Where(x => x.Item1 == '"').ElementAt(5).Item2;

запись функции из этой домашней работы

Это может сделать это:

 Console.WriteLine(str.IndexOf((@"\")+2)+1); 
  • Как работает строковая подстрока в Swift
  • Игнорирование акцентированных букв в сравнении строк
  • Операция XOR с двумя строками в java
  • p: commandbutton action не работает внутри p: dialog
  • Как отформатировать строку Java с начальным нулем?
  • Что такое возврат каретки, перевод строки и фид?
  • Как преобразовать String в ArrayList?
  • Java разделяет строку на массив
  • Неизменяемость строк в Java
  • Как передать переменные из awk в команду оболочки?
  • Равная высота элементов внутри элемента сетки с раскладкой сетки CSS
  • Давайте будем гением компьютера.