Using the ChunkBy extension method on MSDN (any of my simple ToEnumerable extension methods), you can do this with LINQ. The end product looks beautiful, but there are many extension methods to help us:
void Main() { var data= @"This is line 1 Data Line - two Data Line - two two Another line"; var lines = data.Split(new[] {"\r\n", "\n"}, StringSplitOptions.None); var sep = " - "; var linesAndKeys= lines .Select(line => new { line, parts = line.Split(new[] {sep}, StringSplitOptions.None)}) .Select(x=>new { line = x.parts.Length>1 ? string.Join(sep, x.parts.Skip(1)) : x.line, key = x.parts.Length>1 ? x.parts[0] : String.Empty }); var transformedLines= linesAndKeys .ChunkBy(i => i.key) .Select(c => c.Key == String.Empty ? c.Select(s => s.line) : c.Key.ToEnumerable().Concat(c.Select(s=>" - "+s.line))) .Interleave(() => Environment.NewLine.ToEnumerable()) .SelectMany(x => x); var newString = string.Join(Environment.NewLine, transformedLines); Console.WriteLine(newString); } public static class MyExtensions { public static IEnumerable<T> Interleave<T>(this IEnumerable<T> src, Func<T> separatorFactory) { var srcArr = src.ToArray(); for (int i = 0; i < srcArr.Length; i++) { yield return srcArr[i]; if(i<srcArr.Length-1) { yield return separatorFactory(); } } } public static IEnumerable<T> ToEnumerable<T>(this T item) { yield return item; } public static IEnumerable<IGrouping<TKey, TSource>> ChunkBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector) { return source.ChunkBy(keySelector, EqualityComparer<TKey>.Default); } public static IEnumerable<IGrouping<TKey, TSource>> ChunkBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, IEqualityComparer<TKey> comparer) {
EDIT
I added another extension method (Interleave). This is used to alternate new lines where necessary. The result now fully meets your requirements.
How it works:
First we need the keys. If there is a dash, use what is before the first dash, otherwise use string.Empty.
This gives us:
line | key
--------------------------
This is line 1 |
two | Data line
two two | Data line
Another line |
Then, when we have ChunkBy, we have 3 groups (line 1), (line 2, line 3) and (line 4). Each group also has a key.
Now we can use this information to collect data in the required format.