【问题标题】:Insert a carriage return every 64 characters of a string每 64 个字符插入一个回车符
【发布时间】:2014-09-30 04:10:08
【问题描述】:

我有一个这样的 Base64 编码字符串:

SWwgw6l0YWl0IHVuIHBldGl0IG5hdmlyZS [...] 0IG5hdmlyZSA=

输入字符串可以很大(> 1MB)。并且出于互操作性的原因,我需要在该大字符串中每 64 个字符添加一个回车符。

我的第一个猜测是使用 stringbuilder 并每隔 64 个字符使用“AppendLine”方法,如下所示:

string InputB64_Without_CRLF = "SWwgw6l0YWl0IHVuIHBldGl0IG5hdmlyZS [...] 0IG5hdmlyZSA=";
int BufferSize = 64;
int Index = 0;
StringBuilder sb = new StringBuilder();

while (Index < strInput.Length) {
    sb.AppendLine(InputB64_Without_CRLF.Substring(Index, BufferSize));
    Index += BufferSize;
}

string Output_With_CRLF = sb.ToString();

但我担心那部分代码的性能。有没有更好的方法在字符串的某个位置插入一个字符而不重建另一个字符串?

【问题讨论】:

  • 如果使用Convert.ToBase64String,可以使用Base64FormattingOptions.InsertLineBreaks参数
  • 这对我来说似乎是一个合理的方法。您测量过性能问题吗?
  • 我主要关心我的 1MB 数据流从一个字符串复制到另一个字符串。但由于 .NET 字符串是不可变的,我们无法避免这种情况。

标签: c# string


【解决方案1】:

有没有更好的方法在字符串的某个位置插入一个字符而不重建另一个字符串?

.NET 字符串是不可变的,这意味着它们一旦创建就无法修改。

因此,如果你想在字符串中插入字符,没有其他方法只能创建一个新的。而StringBuilder 很可能是最有效的方法,因为它允许您根据需要执行尽可能多的字符串构建步骤,最后只创建一个新字符串。

除非您确实注意到实际场景中的性能问题,否则请保留您当前的解决方案。对我来说它看起来不错,至少从性能的角度来看。

需要考虑的更多细节:

如果您仍然对自己的解决方案不满意,我只能想到一些可能使您当前的解决方案更高效的小事:

  • 预先声明StringBuilders 所需的容量,这样就不必调整其支持字符缓冲区的大小:

    var additionalCharactersCount = Environment.NewLine.Length * (input.Length / 64); 
    var sb = new StringBuilder(capacity: input.Length + additionalCharactersCount);
    
  • 先将完整的输入字符串插入StringBuilder,然后每64个字符重复.Insert(…, Environment.NewLine)

    我完全不确定这是否真的会提高执行速度,但它摆脱.Substring引起的重复字符串创建。自己衡量它是否比您的解决方案更快。

【讨论】:

  • 大声笑,我们有同样的想法,我改变了我的帖子以显示几分钟前。 :)
【解决方案2】:

您的代码并不是低效的,试图节省 100 毫秒或更短的时间通常是不值得的。但是,如果您担心,这里还有另一种更有效的方法,即每 64 个字符插入一个新行(有时是\r\n,而不仅仅是\n)

        string Output_With_CRLF = InputB64_Without_CRLF;
        //Start at last index so that our new line inserts do not move the text, making sure to input every 64th of the original string
        //This looks stupid to divide and multiply again, but it works because it is integer division
        StringBuilder sb = new StringBuilder(InputB64_Without_CRLF);
        for (int i = (InputB64_Without_CRLF.Length / 64) * 64; i >= 64; i -= 64)
            sb.Insert(i, Environment.NewLine);

这只会比您的原始代码更高效一点,您可能不会注意到太多差异。

在与 stakx 交谈后,我有了这个想法。通过使用 StringBuilder,您不会一遍又一遍地创建许多字符串。 StringBuilder 非常高效,可以在不创建更多对象的情况下处理其插入。

【讨论】:

  • 为什么这样会更有效率?字符串是不可变的,插入将为每个插入的换行符构建一个新的 1Mb + 1 字节字符串。我会说他正在做的事情(使用 StringBuilder)比你建议的要好。
  • @ds27680 我改变了我的解决方案。前一个的效率只提高了一点点,因为它没有创建额外的 StringBuilder 对象,并且根据我的经验,插入比子字符串快。
猜你喜欢
  • 2019-04-09
  • 2011-02-09
  • 1970-01-01
  • 1970-01-01
  • 2017-08-24
  • 2011-05-09
  • 2011-03-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多