我希望以简洁的方式执行以下转换.我想改变歌词.输入看起来像这样:
Verse 1 lyrics line 1
Verse 1 lyrics line 2
Verse 1 lyrics line 3
Verse 1 lyrics line 4
Verse 2 lyrics line 1
Verse 2 lyrics line 2
Verse 2 lyrics line 3
Verse 2 lyrics line 4
Run Code Online (Sandbox Code Playgroud)
我想要改变它们,以便每节经文的第一行组合在一起,如:
Verse 1 lyrics line 1
Verse 2 lyrics line 1
Verse 1 lyrics line 2
Verse 2 lyrics line 2
Verse 1 lyrics line 3
Verse 2 lyrics line 3
Verse 1 lyrics line 4
Verse 2 lyrics line 4
Run Code Online (Sandbox Code Playgroud)
歌词显然是未知的,但空白行标志着输入中的经文之间的分歧.
我总是保留一些扩展方法,使这种类型的处理变得非常简单。整个解决方案将比其他解决方案更长,但这些都是有用的方法,一旦您有了扩展方法,那么答案就会非常简短且易于阅读。
首先,有一个 Zip 方法,它接受任意数量的序列:
public static class EnumerableExtensions
{
public static IEnumerable<T> Zip<T>(
this IEnumerable<IEnumerable<T>> sequences,
Func<IEnumerable<T>, T> aggregate)
{
var enumerators = sequences.Select(s => s.GetEnumerator()).ToArray();
try
{
while (enumerators.All(e => e.MoveNext()))
{
var items = enumerators.Select(e => e.Current);
yield return aggregate(items);
}
}
finally
{
foreach (var enumerator in enumerators)
{
enumerator.Dispose();
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后有一个 Split 方法,它与对字符串执行IEnumerable<T>
的操作大致相同:string.Split
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> items,
Predicate<T> splitCondition)
{
using (IEnumerator<T> enumerator = items.GetEnumerator())
{
while (enumerator.MoveNext())
{
yield return GetNextItems(enumerator, splitCondition).ToArray();
}
}
}
private static IEnumerable<T> GetNextItems<T>(IEnumerator<T> enumerator,
Predicate<T> stopCondition)
{
do
{
T item = enumerator.Current;
if (stopCondition(item))
{
yield break;
}
yield return item;
} while (enumerator.MoveNext());
}
Run Code Online (Sandbox Code Playgroud)
一旦你有了这些扩展,解决歌词问题就是小菜一碟:
string lyrics = ...
var verseGroups = lyrics
.Split(new[] { Environment.NewLine }, StringSplitOptions.None)
.Select(s => s.Trim()) // Optional, if there might be whitespace
.Split(s => string.IsNullOrEmpty(s))
.Zip(seq => string.Join(Environment.NewLine, seq.ToArray()))
.Select(s => s + Environment.NewLine); // Optional, add space between groups
Run Code Online (Sandbox Code Playgroud)