С# третий индекс символа в строке
есть ли команда, которая может получить третий индекс символа в строке? Например:
error: file.ext: line 10: invalid command [test:)]
В приведенном выше предложении я хочу указать индекс третьего двоеточия, следующий рядом с 10. Как я могу это сделать? Я знаю string.IndexOf и string.LastIndexOf, но в этом случае я хочу получить индекс символа, когда он используется в третий раз.
Ответы
Ответ 1
String.IndexOf
предоставит вам индекс первого, но имеет перегрузки, дающие начальную точку. Таким образом, вы можете использовать результат первого IndexOf
плюс один в качестве отправной точки для следующего. А затем просто накапливайте индексы достаточное количество раз:
var offset = myString.IndexOf(':');
offset = myString.IndexOf(':', offset+1);
var result = myString.IndexOf(':', offset+1);
Добавьте обработку ошибок, если вы не знаете, что myString
содержит не менее трех двоеточий.
Ответ 2
Вы можете написать что-то вроде:
public static int CustomIndexOf(this string source, char toFind, int position)
{
int index = -1;
for (int i = 0; i < position; i++)
{
index = source.IndexOf(toFind, index + 1);
if (index == -1)
break;
}
return index;
}
РЕДАКТИРОВАТЬ. Очевидно, вы должны использовать его следующим образом:
int colonPosition = myString.CustomIndexOf(',', 3);
Ответ 3
Я предполагаю, что вы хотите разобрать эту строку на разные части.
public static void Main() {
var input = @"error: file.ext: line 10: invalid command [test (: ]";
var splitted = input .Split(separator: new[] {": "}, count: 4, options: StringSplitOptions.None);
var severity = splitted[0]; // "error"
var filename = splitted[1]; // "file.ext"
var line = splitted[2]; // "line 10"
var message = splitted[3]; // "invalid command [test (: ]"
}
Ответ 4
На это уже были ответы несколько очень хороших способов, но я решил попробовать и написать его с помощью Expressions.
private int? GetNthOccurrance(string inputString, char charToFind, int occurranceToFind)
{
int totalOccurrances = inputString.ToCharArray().Count(c => c == charToFind);
if (totalOccurrances < occurranceToFind || occurranceToFind <= 0)
{
return null;
}
var charIndex =
Enumerable.Range(0, inputString.Length - 1)
.Select(r => new { Position = r, Char = inputString[r], Count = 1 })
.Where(r => r.Char == charToFind);
return charIndex
.Select(c => new
{
c.Position,
c.Char,
Count = charIndex.Count(c2 => c2.Position <= c.Position)
})
.Where(r => r.Count == occurranceToFind)
.Select(r => r.Position)
.First();
}
и тесты для подтверждения:
Assert.AreEqual(0, GetNthOccurrance(input, 'h', 1));
Assert.AreEqual(3, GetNthOccurrance(input, 'l', 2));
Assert.IsNull(GetNthOccurrance(input, 'z', 1));
Assert.IsNull(GetNthOccurrance(input, 'h', 10));
Ответ 5
Вы можете вызвать .IndexOf(char, position) для поиска из желаемой позиции, поэтому вы должны называть его 3 раза (но после каждого вызова вы также должны проверить, что-то найдено).
Ответ 6
int pos = -1;
for ( int k = 0; k < 3; ++k )
{
pos = s.indexOf( ':', pos+1 );
// Check if pos < 0...
}
Ответ 7
Немного уродливый, но альтернативный подход (к другим уже опубликованным), который работает:
public int FindThirdColonIndex(string msg)
{
for (int i = 0, colonCount = 0; i < msg.Length; i++)
{
if (msg[i] == ':' && ++colonCount == 3) { return i; }
}
// Not found
return -1;
}
Ответ 8
Вот рекурсивная реализация (для string not char) - как метод расширения, который искажает формат метода (ов) структуры.
Все, что вам нужно сделать, это изменить "строковое значение" на "char значение" в методе расширения и соответствующим образом обновить тесты, и это сработает... Я счастлив сделать это и опубликовать его, если кто-либо интересно?
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)
input.IndexOf(value, startIndex);
return
input.IndexOfNth(value, input.IndexOf(value, startIndex) + 1, --nth);
}
Кроме того, вот некоторые (MBUnit) модульные тесты, которые могут вам помочь (чтобы убедиться, что это правильно):
[Test]
public void TestIndexOfNthWorksForNth1()
{
const string input = "foo<br />bar<br />baz<br />";
Assert.AreEqual(3, input.IndexOfNth("<br />", 0, 1));
}
[Test]
public void TestIndexOfNthWorksForNth2()
{
const string input = "foo<br />whatthedeuce<br />kthxbai<br />";
Assert.AreEqual(21, input.IndexOfNth("<br />", 0, 2));
}
[Test]
public void TestIndexOfNthWorksForNth3()
{
const string input = "foo<br />whatthedeuce<br />kthxbai<br />";
Assert.AreEqual(34, input.IndexOfNth("<br />", 0, 3));
}
Ответ 9
Пожалуйста, смотрите этот ответ по аналогичному вопросу:
fooobar.com/info/305921/...
Он предоставляет метод для поиска индекса n-го вхождения определенного символа в указанной строке.
В вашем конкретном случае это будет реализовано так:
int index = IndexOfNthCharacter("error: file.ext: line 10: invalid command [test:)]", 3, ':');