取字符串的最后n行c#

时间:2012-08-13 21:53:31

标签: c# string string-parsing

我有一个未知长度的字符串

格式为

\nline
\nline
\nline

不知道我怎么能拿走字符串的最后10行 一行由“\ n”分隔

6 个答案:

答案 0 :(得分:13)

随着字符串变大,避免处理无关紧要的字符变得更加重要。使用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;
}

答案 1 :(得分:8)

var result = text.Split('\n').Reverse().Take(10).ToArray();

答案 2 :(得分:6)

Split() \n上的字符串,并获取结果数组的最后10个元素。

答案 3 :(得分:3)

如果这是在文件中并且文件特别大,您可能希望有效地执行此操作。一种方法是向后读取文件,然后只取前10行。您可以看到使用Jon Skeet的MiscUtil库执行此操作here的示例。

var lines = new ReverseLineReader(filename);
var last = lines.Take(10);

答案 4 :(得分:0)

这是一种方法,它的优势在于它不会创建整个源字符串的副本,因此效率很高。大多数代码将与其他通用扩展方法一起放在一个类中,因此最终结果是您可以使用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)也可能效率低下。要解决此问题,可以修改代码以向后搜索字符串。这将消除对TakeLast功能的需要,因为我们可以使用Take。

答案 5 :(得分:0)

节省空间的方法

    private static void PrintLastNLines(string str, int n)
    {
        int idx = str.Length - 1;
        int newLineCount = 0;

        while (newLineCount < n)
        {
            if (str[idx] == 'n' && str[idx - 1] == '\\')
            {
                newLineCount++;
                idx--;
            }

            idx--;
        }

        PrintFromIndex(str, idx + 3);
    }

    private static void PrintFromIndex(string str, int idx)
    {
        for (int i = idx; i < str.Length; i++)
        {
            if (i < str.Length - 1 && str[i] == '\\' && str[i + 1] == 'n')
            {
                Console.WriteLine();
                i++;
            }
            else
            {
                Console.Write(str[i]);
            }
        }

        Console.WriteLine();
    }