105

明らかな組み込みメソッドが欠けていない限り、文字列内でn番目に出現する文字列を取得する最も簡単な方法は何ですか?

ループの反復ごとに開始インデックスを更新することで、 IndexOfメソッドをループできることがわかりました。しかし、このようにすることは私には無駄に思えます。

4

10 に答える 10

110

正規表現/((s).*?){n}/を使用して、 substring の 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して、正規表現エンジンにとって特別な意味を持つ文字を検索できるようにしました。

于 2008-10-09T14:01:58.250 に答える
53

それは基本的にあなたがする必要があることです-または少なくとも、それは最も簡単な解決策です. 「無駄」になるのは、 n メソッド呼び出しのコストだけです。考えてみれば、実際にはどのケースも2回チェックすることはありません。(IndexOf は一致が見つかるとすぐに戻り、中断したところから続行します。)

于 2008-10-09T10:26:51.290 に答える
20

それは基本的にあなたがする必要があることです-または少なくとも、それは最も簡単な解決策です. 「無駄」になるのは、 n メソッド呼び出しのコストだけです。考えてみれば、実際にはどのケースも2回チェックすることはありません。(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<NotSupportedException>(
                () => 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));
        }
    }
}
于 2011-03-22T03:34:26.223 に答える
15
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;
}
于 2009-10-07T04:39:44.747 に答える
1

String.Split()メソッドを操作して、要求されたオカレンスが配列内にあるかどうか、インデックスが必要ない場合はインデックスの値を確認する こともいいでしょう。

于 2014-05-13T09:08:10.327 に答える
-4

これはそれを行うかもしれません:

Console.WriteLine(str.IndexOf((@"\")+2)+1);
于 2012-07-08T07:05:54.497 に答える