编码和空终止字符串
本文关键字:字符串 终止 编码 | 更新日期: 2023-09-27 18:03:12
EDIT:我已经想出了一个解决方案,这里是任何人可能需要它。如果发现错误或添加了其他改进,它可能会在将来更新。最后更新于2015年7月18日。
/// <summary>
/// Decodes a string from the specified bytes in the specified encoding.
/// </summary>
/// <param name="Length">Specify -1 to read until null, otherwise, specify the amount of bytes that make up the string.</param>
public static string GetString(byte[] Source, int Offset, int Length, Encoding Encoding)
{
if (Length == 0) return string.Empty;
var sb = new StringBuilder();
if (Length <= -1)
{
using (var sr = new StreamReader(new MemoryStream(Source, Offset, Source.Length - Offset), Encoding, false))
{
int ch;
while (true)
{
ch = sr.Read();
if (ch <= 0) break;
sb.Append((char)ch);
}
if (ch == -1) throw new Exception("End of stream reached; null terminator not found.");
return sb.ToString();
}
}
else return Encoding.GetString(Source, Offset, Length);
}
我正在升级我的应用程序的内部字符串/编码代码,我遇到了一个小实现问题。
基本上,我想做一个简单的方法,ReadNullTerminatedString。一开始做起来并不难。我使用了编码。IsSingleByte确定单个字符的长度,将读取字节(s),检查是否为0,并根据结果停止读取/继续读取。这就是它变得棘手的地方。UTF8具有可变长度编码。编码。IsSingleByte返回false,但这并不总是正确的,因为它是一个变量编码,字符可以是1字节,所以我的实现基于encoding。IsSingleByte不能在UTF8下工作。
在那一点上,我不确定这种方法是否可以纠正,所以我有了另一个想法。只需在字节上使用编码的GetString方法,为count参数使用字符串的最大长度,然后从返回的字符串中删除零。
这也有一个警告。我必须考虑我的托管应用程序将与从非托管代码返回的字节数组进行交互的情况,当然,在这种情况下,将有一个空终止符,但它后面可能有额外的垃圾字符。例如:"胡说' ' 0 ' oldstring"
ReadNullTerminatedString将是理想的解决方案,在这种情况下,但目前它不能是,如果我想要它支持UTF8。第二种方法也不会奏效——它会减少0,但垃圾仍然存在。
对于c#有什么好的解决方案吗?
您的最佳解决方案是使用TextReader
的实现:
-
StreamReader
如果你正在读取流 -
StringReader
,如果你正在读取字符串
有了这个,你可以读取你的源字节流,无论你喜欢什么编码,每个"字符"将返回给你作为int
:
int ch = reader.Read();
内部魔术是通过c# Decoder
类完成的(它来自于你的编码):
var decoder = Encoding.UTF7.GetDecoder();
Decoder
类需要一个短数组缓冲区。幸运的是,StreamReader
知道如何保持缓冲区的填充和一切工作。
未经尝试,未经测试,只是碰巧看起来像c#:
String ReadNullTerminatedString(Stream stm, Encoding encoding)
{
StringBuilder sb = new StringBuilder();
TextReader rdr = new StreamReader(stm, encoding);
int ch = rdr.Read();
while (ch > 0) //returns -1 when we've hit the end, and 0 is null
{
sb.AppendChar(Char(ch));
int ch = rdr.Read();
}
return sb.ToString();
}
标题>注:任何发布到公共领域的代码。不需要署名