17

文字列内で特定の文字が N 番目に出現するインデックスを返す関数を作成しようとしています。

これが私の試みです:

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' または何を渡しますか?

4

9 に答える 9

43

そうしないでください。IndexOfどこから開始するかを指定する 2 番目のパラメーターを取ります。

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;
}
于 2012-07-06T13:29:27.407 に答える
26

これらすべての部分文字列を取得することは、私にはかなり無駄に思えます。自分をループさせてみませんか?

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;
}

( IndexOfminitech のソリューションのようにループで使用することを検討しましたが、少し手間がかかると判断しました。もちろん、どちらでも構いません。どちらも基本的に同じ作業を行い、各文字を 1 回だけチェックしますIndexOf。より読みやすくなります。)

于 2012-07-06T13:29:03.790 に答える
14

LINQ を使用してa、文字列の 5 番目のインデックスを検索します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;
于 2012-07-06T13:33:55.977 に答える
6

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();
于 2012-07-06T13:55:37.600 に答える
1

テストされていませんが、次のようなものが動作するはずです:

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;
}
于 2012-07-06T13:34:20.663 に答える
1

一連の部分文字列を作成する代わりに、開始インデックスを取るオーバーロードを使用してIndexOfみませんか? これにより、簡単になり (最終的なインデックスを調整する必要がなくなります)、より効率的になります (一連の部分文字列を割り当てる必要がなくなります)。

于 2012-07-06T13:28:50.210 に答える
0

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; }
    }

部分文字列などはなく、非常に効率的である必要があります。指定された文字列をスキャンしてカウントを維持するだけです。

于 2012-07-06T18:46:24.747 に答える