Here you go - it works any combination of separators in any order, which also allows in a situation where the separator is not actually found in the string. It took me a while to come up with this and, posting it, looks more complicated than any other answer!
Okay, I'll keep it here anyway.
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 - ie there 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; } }
And here is a test you can use to test it:
[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)); }
Please note that I suggested that you need to do something with the elements of the array in order to manipulate the individual lines before joining them together again - otherwise presumably you just save the original line!
The method builds a dynamic format string. There is no guarantee of effectiveness :)