Получить индекс 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); 
  • Алгоритм поиска нескольких совпадений строк
  • Строка макроопределения
  • Есть ли на C # String Tokenizer, например, Java?
  • Замена строк в java, аналогично шаблону скорости
  • Создайте переменную java.lang.String
  • Сортировка одной строки в Java
  • Что подразумевается под неизменным?
  • Удалить пробел из строки в Objective-C
  • Разделение строки Java удалено пустым значением
  • Как форматировать строки в Java
  • Как преобразовать String в ArrayList?
  • Interesting Posts

    Где я должен делать инъекцию с помощью Ninject 2+ (и как я могу упорядочить свои модули?)

    Подключение к удаленному рабочему столу невозможно подключиться к Windows Server 2012

    Считать количество кадров ffmpeg

    Существует ли программное обеспечение для регистрации всего использования для загрузки / выгрузки?

    R: ggplot не работает, если он находится внутри цикла for, хотя он работает вне него

    Ошибка Windows Update с кодом 80244019

    Как получить строку между двумя символами?

    Зависимости Maven не отображаются в WEB-INF / lib

    scala: memoize функция независимо от того, сколько аргументов функция принимает?

    Как установить файл APK в эмуляторе Android?

    Можете ли вы заставить Visual Studio работать в качестве администратора в Windows 8?

    Windows, отображающая загрузочную информацию вместо загрузки

    Хранение файлов жесткого диска в виртуальной памяти без изменения путей к файлам

    Использование FFMpeg для вырезания видео в 2-минутные клипы

    Какой формат «undf»?

    Давайте будем гением компьютера.