LINQ中棘手的字符串转换(希望如此)

Lar*_*nal 5 c# linq string

我希望以简洁的方式执行以下转换.我想改变歌词.输入看起来像这样:

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)

歌词显然是未知的,但空白行标志着输入中的经文之间的分歧.

Aar*_*ght 3

我总是保留一些扩展方法,使这种类型的处理变得非常简单。整个解决方案将比其他解决方案更长,但这些都是有用的方法,一旦您有了扩展方法,那么答案就会非常简短且易于阅读。

首先,有一个 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)