我正在使用一个低级本机 API,我在其中发送一个不安全的字节缓冲区指针来获取一个 c 字符串值。
所以它给了我
// using byte[255] c_str
string s = new string(Encoding.ASCII.GetChars(c_str));
// now s == "heresastring\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0(etc)";
所以很明显我做得不对,我如何摆脱多余的?
.NET 字符串不是以空值结尾的(正如您可能已经猜到的那样)。因此,您可以像对待任何普通字符一样对待 '\0'。正常的字符串操作将为您解决问题。以下是一些(但不是全部)选项。
s = s.Trim('\0');
s = s.Replace("\0", "");
var strings = s.Split(new char[] {'\0'}, StringSplitOptions.RemoveEmptyEntries);
如果您确实想在第一个空字符之后丢弃任何值,这可能对您更有效。但请注意,它仅适用于实际包含空字符的字符串。
s = s.Substring(0, Math.Max(0, s.IndexOf('\0')));
可能有一个选项可以在转换中去除 NUL。
除此之外,您可能可以使用以下方法对其进行清理:
s = s.Trim('\0');
...或者,如果您认为在某些 NUL 之后可能有非 NUL 字符,这可能更安全:
int pos = s.IndexOf('\0');
if (pos >= 0)
s = s.Substring(0, pos);
// s == "heresastring\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0(etc)"
s = s.Split(new[] { '\0' }, 2)[0];
// s == "heresastring"
其中一种System.Runtime.InteropServices.Marshall.PtrToString*
方法怎么样?
Marshal.PtrToStringAnsi
- 将非托管 ANSI 字符串中直到第一个空字符的所有字符复制到托管字符串,并将每个 ANSI 字符扩展为 Unicode。
Marshal.PtrToStringUni
- 分配一个托管字符串并将全部或部分复制到非托管 Unicode 字符串的第一个空值中。
最安全的方法是使用:
s = s.Replace("\0", "");
我相信 \0 在 ascii 中是“null”——你确定你得到的字符串实际上是 ascii 编码的吗?
从 .NET Core 2.1 开始,可以使用以下内容来帮助防止对中间数组或字符串进行不必要的分配:
var bytesAsSpan = bytes.AsSpan();
var terminatorIndex = bytesAsSpan.IndexOf(byte.MinValue);
var s = Encoding.ASCII.GetString(bytesAsSpan.Slice(0, terminatorIndex));
这实际上是需要 .NET Core 2.1 或更高版本的最后一行,因为那Encoding.GetString(ReadOnlySpan<byte>)
是引入重载的时候。可以Span
使用包进行基于操作,System.Memory
但Encoding.GetString
不会暴露接受的重载ReadOnlySpan<byte>
,因此最后一行必须分配一个数组:
var s = Encoding.ASCII.GetString(bytesAsSpan.Slice(0, terminatorIndex).ToArray());