11

長さのわからない紐があります

それはフォーマットにあります

\nline
\nline
\nline

どのくらいの長さかわからなくても、文字列の最後の 10 行を "\n" で区切られた行にする方法を教えてください。

4

6 に答える 6

14

文字列が大きくなるにつれて、重要でない文字の処理を避けることがより重要になります。string.Split文字列全体を処理する必要があるため、使用するアプローチは非効率的です。効率的な解決策は、ストリングを後ろから通す必要があります。これが正規表現のアプローチです。

List<string>結果が返される前に逆にする必要があるため、 を返すことに注意してください(したがって、Insertメソッドを使用します) 。

private static List<string> TakeLastLines(string text, int count)
{
    List<string> lines = new List<string>();
    Match match = Regex.Match(text, "^.*$", RegexOptions.Multiline | RegexOptions.RightToLeft);

    while (match.Success && lines.Count < count)
    {
        lines.Insert(0, match.Value);
        match = match.NextMatch();
    }

    return lines;
}
于 2012-08-14T03:32:20.010 に答える
9
var result = text.Split('\n').Reverse().Take(10).ToArray();
于 2012-08-13T22:00:51.703 に答える
6

Split()の文字列\nを取得し、結果の配列の最後の 10 個の要素を取得します。

于 2012-08-13T21:55:51.053 に答える
3

If this is in a file and the file is particularly large, you may want to do this efficiently. A way to do it is to read the file backwards, and then only take the first 10 lines. You can see an example of using Jon Skeet's MiscUtil library to do this here.

var lines = new ReverseLineReader(filename);
var last = lines.Take(10);
于 2012-08-13T22:07:53.110 に答える
0

ソース文字列全体のコピーを作成しないのでかなり効率的であるという利点がある方法の 1 つを次に示します。ほとんどのコードは、他の汎用拡張メソッドと一緒にクラスに配置されるため、最終的には 1 行のコードで実行できます。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string x = "a\r\nb\r\nc\r\nd\r\ne\r\nf\r\ng\r\nh\r\ni\r\nj\r\nk\r\nl\r\nm\r\nn\r\no\r\np";
            foreach(var line in x.SplitAsEnumerable("\r\n").TakeLast(10))
                Console.WriteLine(line);
            Console.ReadKey();
        }
    }

    static class LinqExtensions
    {
        public static IEnumerable<string> SplitAsEnumerable(this string source)
        {
            return SplitAsEnumerable(source, ",");
        }

        public static IEnumerable<string> SplitAsEnumerable(this string source, string seperator)
        {
            return SplitAsEnumerable(source, seperator, false);
        }

        public static IEnumerable<string> SplitAsEnumerable(this string source, string seperator, bool returnSeperator)
        {
            if (!string.IsNullOrEmpty(source))
            {
                int pos = 0;
                do
                {
                    int newPos = source.IndexOf(seperator, pos, StringComparison.InvariantCultureIgnoreCase);
                    if (newPos == -1)
                    {
                        yield return source.Substring(pos);
                        break;
                    }
                    yield return source.Substring(pos, newPos - pos);
                    if (returnSeperator) yield return source.Substring(newPos, seperator.Length);
                    pos = newPos + seperator.Length;
                } while (true);
            }
        }

        public static IEnumerable<T> TakeLast<T>(this IEnumerable<T> source, int count)
        {
            List<T> items = new List<T>();
            foreach (var item in source)
            {
                items.Add(item);
                if (items.Count > count) items.RemoveAt(0);
            }
            return items;
        }
    }
}

編集:文字列全体を反復するため、これはより効率的である可能性があることが指摘されています。また、リストを使用した RemoveAt(0) もおそらく非効率的だと思います。これを解決するには、文字列を逆方向に検索するようにコードを変更します。これにより、Take だけを使用できるため、TakeLast 関数が不要になります。

于 2012-08-13T22:18:30.887 に答える