Получить индекс n-го вхождения char в строку
Я пытаюсь создать функцию, которая возвращает индекс N-го вхождения данного char в строку.
Вот моя попытка:
private int IndexOfNth(string str, char c, int n)
{
int index = str.IndexOf(c) + 1;
if (index >= 0)
{
string temp = str.Substring(index, str.Length - index);
for (int j = 1; j < n; j++)
{
index = temp.IndexOf(c) + 1;
if (index < 0)
{
return -1;
}
temp = temp.Substring(index, temp.Length - index);
}
index = index + (str.Length);
}
return index;
}
Это должно найти первое вхождение, отрубить эту переднюю часть строки, найти первое вхождение из новой подстроки и продолжать и продолжать, пока не получит индекс n-го вхождения. Однако мне не удалось понять, как индекс конечной подстроки будет смещен от исходного фактического индекса в исходной строке. Как это сделать?
Также, как побочный вопрос, если я хочу, чтобы char был символом табуляции, передаю эту функцию '\ t' или что?
Ответы
Ответ 1
Используя LINQ, найдите индекс 5'th a
в строке aababaababa
:
var str = "aababaababa";
var ch = 'a';
var n = 5;
var result = str
.Select((c, i) => new { c, i })
.Where(x => x.c == ch)
.Skip(n - 1)
.FirstOrDefault();
return result != null ? result.i : -1;
Ответ 2
Не делай этого; IndexOf
принимает второй параметр, который указывает, с чего начать.
private static int IndexOfNth(string str, char c, int n) {
int s = -1;
for (int i = 0; i < n; i++) {
s = str.IndexOf(c, s + 1);
if (s == -1) break;
}
return s;
}
Ответ 3
Взятие всех этих подстрок кажется мне довольно расточительным. Почему бы просто не зациклиться?
private int IndexOfNth(string str, char c, int n)
{
int remaining = n;
for (int i = 0; i < str.Length; i++)
{
if (str[i] == c)
{
remaining--;
if (remaining == 0)
{
return i;
}
}
}
return -1;
}
(я рассмотрел использование IndexOf
в цикле, как решение minitech, но решил, что это было немного странно. Конечно, конечно. Оба в основном выполняют ту же работу, только когда-либо проверяя каждый символ один раз. Использование IndexOf
может быть немного более эффективным, но идти в зависимости от того, что вы найдете более читаемым.)
Ответ 4
Я сначала думаю о том, как получить доступ к коллекции с помощью Linq.
// 0-based n.
char result = str
.Where(x => x == c)
.Skip(n)
.FirstOrDefault();
Затем я распакую linq и добавлю индексированную итерацию.
int foundCount = -1;
for(int position = 0; position < str.Length; position++)
{
char x = str[position];
if (x == c)
{
foundCount += 1;
// 0-based n
if (foundCount == n)
{
return position;
}
}
}
return -1;
Тогда я думаю о том: что, если этот метод вернет все индексы, чтобы я мог их запросить:
public IEnumerable<int> IndexesOf(string str, char c)
{
for(int position = 0; position < str.Length; position++)
{
char x = str[position];
if (x == c)
{
yield return position;
}
}
}
Вызывается:
int position = IndexesOf(str, c)
.Skip(n) // 0-based n
.DefaultIfEmpty(-1)
.First();
Ответ 5
Вместо того, чтобы создавать кучу подстрок, почему бы не использовать перегрузку IndexOf
, которая принимает начальный индекс? Это будет проще (вам не придется настраивать конечный индекс) и более эффективны (вам не нужно выделять кучу подстрок).
Ответ 6
Не тестировалось, но что-то вроде этого должно работать:
private int IndexOfNth(string str, char c, int n)
{
int index = -1;
while (n-- > 0)
{
index = str.IndexOf(c, index + 1);
if (index == -1) break;
}
return index;
}
Ответ 7
Не видел, чтобы кто-нибудь использовал CharEnumerator еще...
public Int32 getNthIndex(string str, char c, Int32 n)
{
Int32 index = 0;
Int32 count = 0;
if (str != null && str.Length > 0 && !(n < 1))
{
CharEnumerator scanner = str.GetEnumerator();
while (scanner.MoveNext())
{
if (scanner.Current == c) { count++; }
if (count == n) { break; }
index++;
}
if (count < n) { index = -1; }
}
if (count == 0) { return -1; } else { return index; }
}
Должно быть довольно эффективно, подстроки или что-то еще, просто просматривайте строку, которую вы даете, и держите счет.
Ответ 8
Вы можете использовать следующий метод, который вернет n-ое вхождение указанного символа в указанной строке.
public static int IndexOfNthCharacter(string str, int n, char c) {
int index = -1;
if (!str.Contains(c.ToString()) || (str.Split(c).Length-1 < n)) {
return -1;
}
else {
for (int i = 0; i < str.Length; i++) {
if (n > 0) {
index++;
}
else {
return index;
}
if (str[i] == c) {
n--;
}
}
return index;
}
}
Обратите внимание, что если искомый символ не существует в строке, которую вы ищете, или номер поиска, который вы ищете, больше, чем тот, что существует в строке, тогда этот метод вернет -1.