使用C#删除字符串中的最后两行?

使用C#删除字符串中的最后两行?,c#,linq,C#,Linq,我想从我拥有的一些总是变化的字符串中删除最后两行: Hello How Are you ? im fine Thanks some info some info 对于这个例子,假设我有上面的字符串 我想删除最后两行 “一些信息” 这就是我在下面尝试的 正如我所说的,最后两行总是以文本形式出现,这就是为什么我使用“Environment.NewLine” string sem = mtstring = mtstring (mtstring .TrimEnd().LastIndexOf(Envir

我想从我拥有的一些总是变化的字符串中删除最后两行:

Hello How Are you ?
im fine Thanks
some info
some info
对于这个例子,假设我有上面的字符串 我想删除最后两行 “一些信息”

这就是我在下面尝试的 正如我所说的,最后两行总是以文本形式出现,这就是为什么我使用“Environment.NewLine”

string sem = mtstring = mtstring (mtstring .TrimEnd().LastIndexOf(Environment.NewLine));
            string Good = sem = sem.Remove(sem.TrimEnd().LastIndexOf(Environment.NewLine));
改为:

string sem = mtstring.Remove(mtstring.LastIndexOf(Environment.NewLine));
string Good = sem.Remove(sem.LastIndexOf(Environment.NewLine));

假设您有
Environment.NewLine
作为分隔符,但也可以更改为使用任何分隔符

var str = "Hello How Are you ?" + Environment.NewLine +
          "im fine Thanks" + Environment.NewLine +
          "some info" + Environment.NewLine +
          "some info";

var split = str.Split(new [] { Environment.NewLine }, StringSplitOptions.None).ToList();

Console.WriteLine(string.Join(Environment.NewLine, split.Take(split.Count - 2)));
// Hello How Are you ?
// im fine Thanks

n.b.注意新行,在Windows上,它是
\r\n
。Unix和Mac分别为
\n
\r

这里有一条单行线:

string good = string.Join(Environment.NewLine, mtstring.Split(Environment.NewLine).Reverse().Skip(2).Reverse());
编辑:

我做了下面的测试来测试时间效率,这表明(正如@TheodorZoulias所指出的)这种方法是非常无效的,所以在更大的数据集上使用因果关系

class Program
{
  static void Main(string[] args)
  {
    var testString = string.Join(Environment.NewLine, Enumerable.Range(0, 1000000));
    var oldArray = testString.Split();

    Stopwatch stopwatch = Stopwatch.StartNew();
    var newString = string.Join(Environment.NewLine, oldArray);
    stopwatch.Stop();
    Console.WriteLine($"String length: {newString.Length}");
    Console.WriteLine($"Time elapsed: {stopwatch.ElapsedMilliseconds} ms");

    stopwatch = Stopwatch.StartNew();
    newString = string.Join(Environment.NewLine, oldArray.Reverse().Skip(2).Reverse());
    stopwatch.Stop();
    Console.WriteLine($"String length: {newString.Length}");
    Console.WriteLine($"Time elapsed: {stopwatch.ElapsedMilliseconds} ms");
  }
}
输出:

Hello How Are you ?

im fine Thanks
字符串长度:9888886

时间:45毫秒

字符串长度:9888876

时间:188毫秒


总之,double
Reverse
调用非常昂贵,与仅拆分和连接字符串相比,执行时间增加了四倍,这本身并不是一项廉价的任务。

您可以尝试以下方法:

//Create list of strings for each line in mtstring
List<string> lines = mtstring.Split(
                        new string[] {"\n", "\r"}, 
                        StringSplitOptions.None
                ).ToList();

//Take a subset of these lines (Total - 2)
lines = lines.GetRange(0, lines.Count-2);

//Rejoin the list as a string
string Good = string.Join("\n", lines);
快速(写入而非执行)解决方案是使用Linq:

var input = "Hello How Are you ?\r\nim fine Thanks\r\nsome info\r\nsome info";
var res1 = string.Join(Environment.NewLine, input
    .Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries)
    .Reverse()
    .Skip(2)
    .Reverse());
更理想的解决方案是使用
StringBuilder

var sb = new StringBuilder();
var temp = input.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
for (var i = 0; i < temp.Length - 2; ++i)
    sb.AppendLine(temp[i]);

var res2 = sb.ToString();
var sb=new StringBuilder();
var temp=input.Split(Environment.NewLine.ToCharArray(),StringSplitOptions.RemoveEmptyEntries);
对于(变量i=0;i<温度长度-2;++i)
某人(临时工[本人]);
var res2=sb.ToString();
机器人
res1
res2
将:

你好吗?
我很好,谢谢


为提高效率而实施。希望不是马车

public static string RemoveLinesFromTheEnd(string source, int linesToRemove)
{
    var separators = new char[] { '\r', '\n' };
    int pos = source.Length;
    for (int i = 0; i < linesToRemove; i++)
    {
        pos = source.LastIndexOfAny(separators, pos - 1);
        if (pos > 0 && source[pos - 1] == '\r' && source[pos] == '\n') pos--;
        if (pos <= 0) break;
    }
    return pos < 0 ? "" : source.Substring(0, pos);
}
如果添加Microsoft的“System.Interactive”NuGet软件包,则可以执行以下操作:

string Good =
    String.Join(
        Environment.NewLine,
        mtstring.Split(Environment.NewLine.ToArray()).SkipLast(2));

Environment.NewLine!=Random.Text
-很清楚,“新行”在某种程度上就是这样的,ala
\r\n
。不是一堆随机的文本。可能是重复的,我不是故意要随机上课……这似乎效率很低。Reverse为源代码创建了一个缓冲区,您调用了它两次。我认为您的说法不对,因为
Reverse
使用延迟执行,因此对象实际上并不包含所有数据,只包含执行它所需的数据。我做了一个测试,看到我编辑的答案。你可以查看反向的实现。它所做的是缓冲源的所有元素,然后向后枚举缓冲区。当然,您是正确的。谢谢你纠正我,我已经更新了我的测试和结论。我确实知道这次讨论中提供的所有事实,但从一些额外的(和未满足的)假设中得出了所有错误的结论。哈哈!是的,LINQ的延迟执行很棘手。它仍然不时地咬我。:-)你的最新答案现在是有价值的,向上投票。酷。的实现很有趣。它使用一个缓冲区,缓冲区大小为要跳过的行的大小。
string Good =
    String.Join(
        Environment.NewLine,
        mtstring.Split(Environment.NewLine.ToArray()).SkipLast(2));