明らかな組み込みメソッドがない場合を除いて、文字列内のn番目の文字列を取得する最も速い方法は何ですか?
ループの各反復で開始インデックスを更新することにより、IndexOfメソッドをループできることを理解しています。しかし、この方法でそれを行うことは私にとっては無駄に思えます。
明らかな組み込みメソッドがない場合を除いて、文字列内のn番目の文字列を取得する最も速い方法は何ですか?
ループの各反復で開始インデックスを更新することにより、IndexOfメソッドをループできることを理解しています。しかし、この方法でそれを行うことは私にとっては無駄に思えます。
回答:
それは基本的にあなたがする必要があることです-または、少なくとも、それは最も簡単な解決策です。「無駄」になるのは、n回のメソッド呼び出しのコストだけです。考えてみれば、実際にケースを2回チェックすることはありません。(IndexOfは一致が見つかるとすぐに戻り、中断したところから続行します。)
StringUtils.ordinalIndexOf()
。すべてのLinqおよびその他の素晴らしい機能を備えたC#には、これに対するサポートが組み込まれていません。そして、はい、パーサーとトークナイザーを扱っている場合、サポートが不可欠です。
string
:)
正規表現/((s).*?){n}/
を使用して、n番目に出現するsubstringを検索できます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
正規表現エンジンに特別な意味を持つ文字を検索できるように、元のソリューションに追加しました。
value
か?私の場合は、ドットを探していたmsdn.microsoft.com/en-us/library/...
それは基本的にあなたがする必要があることです-または、少なくとも、それは最も簡単な解決策です。「無駄」になるのは、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));
}
}
}
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;
}
index
最初に-1に設定することで修正できます。
"BOB".IndexOf("B")
0が返された場合、この関数は次のように機能しますIndexOfOccurence("BOB", "B", 1)
IndexOfOccurence
かどうかをチェックしませんs
ですnull
。そしてString.IndexOf(文字列、のInt32)がスローされますArgumentNullException
場合match
ですnull
。
おそらく、String.Split()
メソッドを操作して、要求されたオカレンスが配列内にあるかどうか、インデックスが必要ないがインデックスの値がどうかを確認 するのも良いでしょう。
いくつかのベンチマークの後、これは最も単純で最も効率的なソリューションのようです
public static int IndexOfNthSB(string input,
char value, int startIndex, int nth)
{
if (nth < 1)
throw new NotSupportedException("Param 'nth' must be greater than 0!");
var nResult = 0;
for (int i = startIndex; i < input.Length; i++)
{
if (input[i] == value)
nResult++;
if (nResult == nth)
return i;
}
return -1;
}
トッドの答えは多少単純化することができます。
using System;
static class MainClass {
private static int IndexOfNth(this string target, string substring,
int seqNr, int startIdx = 0)
{
if (seqNr < 1)
{
throw new IndexOutOfRangeException("Parameter 'nth' must be greater than 0.");
}
var idx = target.IndexOf(substring, startIdx);
if (idx < 0 || seqNr == 1) { return idx; }
return target.IndexOfNth(substring, --seqNr, ++idx); // skip
}
static void Main () {
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 1));
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 2));
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 3));
Console.WriteLine ("abcbcbcd".IndexOfNth("bc", 4));
}
}
出力
1
3
5
-1