C # третий индекс символа в строке - PullRequest
11 голосов
/ 02 января 2011

есть ли команда, которая может получить третий индекс символа в строке?Например:

error: file.ext: line 10: invalid command [test:)]

В приведенном выше предложении я хочу указать индекс 3-го двоеточия, следующий за 10. Как я могу это сделать?Я знаю о string.IndexOf и string.LastIndexOf, но в этом случае я хочу получить индекс символа, когда он используется в третий раз.

Ответы [ 9 ]

13 голосов
/ 02 января 2011

String.IndexOf даст вам индекс первого, но имеет перегрузки, дающие отправную точку.Таким образом, вы можете использовать результат первого IndexOf плюс один в качестве отправной точки для следующего.А затем просто накапливайте индексы достаточное количество раз:

var offset = myString.IndexOf(':');
offset = myString.IndexOf(':', offset+1);
var result = myString.IndexOf(':', offset+1);

Добавьте обработку ошибок, если только вы не знаете, что myString содержит как минимум три двоеточия.

9 голосов
/ 02 января 2011

Вы можете написать что-то вроде:

    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);
4 голосов
/ 02 января 2011

Полагаю, вы хотите разобрать эту строку на разные части.

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 (: ]"
}
2 голосов
/ 02 января 2011

На это уже ответили несколько очень хороших способов - но я решил попробовать написать это с помощью 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));
0 голосов
/ 28 сентября 2017

Пожалуйста, посмотрите этот ответ на похожий вопрос: https://stackoverflow.com/a/46460083/7673306
Он предоставляет метод для поиска индекса n-го вхождения определенного символа в обозначенной строке.

В вашем конкретном случае это будет реализовано так:

int index = IndexOfNthCharacter("error: file.ext: line 10: invalid command [test:)]", 3, ':');
0 голосов
/ 22 марта 2011

Вот рекурсивная реализация (для строки, а не char) - как метод расширения, имитирующий формат метода (ов) фреймворка.

Все, что вам нужно сделать, это изменить «строковое значение» на «char value 'в методе расширения и обновите тесты соответственно, и это будет работать ... Я рад сделать это и опубликовать его, если кому-то интересно?

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));
}
0 голосов
/ 02 января 2011

Немного некрасиво, но альтернативный подход (к уже опубликованным), который работает:

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;
}
0 голосов
/ 02 января 2011
int pos = -1;
for ( int k = 0; k < 3; ++k )
{
  pos = s.indexOf( ':', pos+1 );
  // Check if pos < 0...
}
0 голосов
/ 02 января 2011

Вы можете вызывать .IndexOf (char, position) для поиска из нужной позиции, поэтому вам следует вызывать ее 3 раза (но после каждого вызова вы также должны проверять, найдено ли что-то).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...