これで、区切り文字の任意の組み合わせが任意の順序で機能し、文字列内に区切り文字が実際に見つからない状況も可能になります。これを思い付くのに少し時間がかかりました、そしてそれを投稿したので、それは他のどの答えよりも複雑に見えます!
ああ、とにかくここに置いておきます。
public static string SplitAndReJoin(string str, char[] delimiters,
Func<string[], string[]> mutator)
{
//first thing to know is which of the delimiters are
//actually in the string, and in what order
//Using ToArray() here to get the total count of found delimiters
var delimitersInOrder = (from ci in
(from c in delimiters
from i in FindIndexesOfAll(str, c)
select new { c, i })
orderby ci.i
select ci.c).ToArray();
if (delimitersInOrder.Length == 0)
return str;
//now split and mutate the string
string[] strings = str.Split(delimiters);
strings = mutator(strings);
//now build a format string
//note - this operation is much more complicated if you wish to use
//StringSplitOptions.RemoveEmptyEntries
string formatStr = string.Join("",
delimitersInOrder.Select((c, i) => string.Format("{{{0}}}", i)
+ c));
//deals with the 'perfect' split - i.e. there's always two values
//either side of a delimiter
if (strings.Length > delimitersInOrder.Length)
formatStr += string.Format("{{{0}}}", strings.Length - 1);
return string.Format(formatStr, strings);
}
public static IEnumerable<int> FindIndexesOfAll(string str, char c)
{
int startIndex = 0;
int lastIndex = -1;
while(true)
{
lastIndex = str.IndexOf(c, startIndex);
if (lastIndex != -1)
{
yield return lastIndex;
startIndex = lastIndex + 1;
}
else
yield break;
}
}
そして、これを検証するために使用できるテストは次のとおりです。
[TestMethod]
public void TestSplitAndReJoin()
{
//note - mutator does nothing
Assert.AreEqual("a,b", SplitAndReJoin("a,b", ",".ToCharArray(), s => s));
//insert a 'z' in front of every sub string.
Assert.AreEqual("zaaa,zbbbb.zccc|zdddd:zeee", SplitAndReJoin("aaa,bbbb.ccc|dddd:eee",
",.|:".ToCharArray(), s => s.Select(ss => "z" + ss).ToArray()));
//re-ordering of delimiters + mutate
Assert.AreEqual("zaaa,zbbbb.zccc|zdddd:zeee", SplitAndReJoin("aaa,bbbb.ccc|dddd:eee",
":|.,".ToCharArray(), s => s.Select(ss => "z" + ss).ToArray()));
//now how about leading or trailing results?
Assert.AreEqual("a,", SplitAndReJoin("a,", ",".ToCharArray(), s => s));
Assert.AreEqual(",b", SplitAndReJoin(",b", ",".ToCharArray(), s => s));
}
配列の要素を使って何かを実行し、個々の文字列を操作してから再度結合する必要があると想定していることに注意してください。そうしないと、おそらく元の文字列を保持することになります。
このメソッドは、動的フォーマット文字列を作成します。ここでは効率に関する保証はありません:)