如何将字符串转换为以空字符结尾的字符串?

3

如何将简单字符串转换为以null结尾的字符串?

示例:

示例字符串:"测试消息"
以下是字节:

54 65 73 74 20 6D 65 73 73 61 67 65

我需要像下面这样的字节字符串:

54 00 65 00 73 00 74 00 20 00 6D 00 65 00 73 00 73 00 61 00 67 00 65 00 00

我可以使用循环,但代码会很丑陋。如何使用原生方法进行此转换?

4
"string with bytes" 不是一个顺理成章的说法。字符串由字符组成,而非字节。 - Jon Skeet
好的。"带有十六进制代码的字符字符串,就像这样"。 - Johnson
我认为这段代码太丑了:Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(s + "\0"))。不过它确实能正常工作。 - Johnson
2
我甚至不确定那真的是你想要的。一个字符串由UTF-16码元组成。如果你实际上需要像所示的以字节形式发送字符串的编码形式,那就是另一回事了……请给出更多上下文。 - Jon Skeet
4个回答

13

看起来您需要一个以空字符结尾的Unicode字符串。如果该字符串存储在变量str中,那么这应该可以正常工作:

var bytes = System.Text.Encoding.Unicode.GetBytes(str + "\0");

(查看运行结果。)

需要注意的是,生成的数组最后会有三个零字节。这是因为Unicode使用两个字节来表示字符。第一个零是原始字符串中最后一个字符的一半,接下来的两个零是Unicode编码空字符'\0'的方式。(换句话说,我的代码比你最初指定的多了一个空字符,但这可能是你实际想要的。)


4
@user2264990,您要求字节。C#中的字符串包含字符,而不是字节。请澄清您的问题。解释一下为什么您需要这个可能会有帮助。 - cdhowie
我认为这段代码太丑了...不是吗?Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(s + "\0")) - Johnson
@user2264990 这将产生与 (s + "\0") 相同的结果。大多数情况下,对于任何编码 XEncoding.X.GetString(Encoding.X.GetBytes(s)) == s - cdhowie
2
@user2264990:是的,那太丑了。如果你只想要字符串,只需使用s = s + "\0"...但这不会将字符串与Unicode NUL字符交错,我怀疑你也不想要那样。但你需要在这里提供更多上下文。 - Jon Skeet

6
一些关于C#字符串的背景知识是一个好的起点。
C#字符串内部结构与C字符串不同。 a)它是Unicode,就像'char'一样 b)它没有以null结尾 c)它包括许多在C/C++中需要使用的实用函数。
它是如何避免null结尾的呢?简单!在内部,C#字符串管理一个char数组。C#数组是结构体,而不是指针(就像在C/C++中)。因此,它们知道自己的长度。在C/C++中的Null结尾是必需的,这样字符串实用函数如strcmp()就能够检测到内存中的字符串结束。
null字符在C#中确实存在。
string content = "This is a message!" + '\0';

这将给你一个以空终止符结尾的字符串。重要的是,空字符是不可见的,不会出现在任何输出中,它只会在调试窗口中显示。当你将字符串转换为字节数组(用于保存到磁盘和其他IO操作)时,它也会存在其中。但如果你执行Console.WriteLine(content),它就不可见了。

你应该明白为什么需要这个空终止符,以及为什么要避免使用循环结构来获取所需内容。在c#中,除非你最终要转换为字节数组,否则空终止符对于字符串而言是相当无用的。通常你只会在想要将字符串发送到本机方法、网络或usb设备时才这样做。

同样重要的是要意识到你如何获得字节。在C/C++中,char作为1字节(8位)存储,编码为ANSI。在C#中,编码为Unicode,占用两个字节(16位)。Jon Skeet 的回答展示了如何在Unicode下获取字节。


1
实际上,.NET字符串也是以空字符结尾的(但这并不妨碍它们包含嵌入的空字符)。如果您将指针设置为字符串中的第一个字符,您会发现在其末尾有一个隐藏的空字符。我认为这不是 .NET API 的一部分,但在内部被广泛依赖。 - Cameron
@Cameron 这是个好发现。我一直想知道为什么 Encoding.Getbytes 会终止。 - Gusdor

1
舌尖上的幽默但可能有用的回答。如果您想在屏幕上输出像您展示的那样的十六进制内容,则需要遵循以下两个步骤:
  1. 将字符串(末尾带有空字符“\ 0”)转换为字节数组
  2. 将字节字符串表示形式转换为十六进制
  3. 插入空格
  4. 输出到屏幕

试试这个:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace stringlulz
{
    class Program
    {
        static void Main(string[] args)
        {
            string original = "Test message";

            byte[] bytes = System.Text.Encoding.Unicode.GetBytes(original + '\0');

            var output = bytes.Aggregate(new StringBuilder(), (s, p) => s.Append(p.ToString("x2") + ' '), s => { s.Length--; return s; });


            Console.WriteLine(output.ToString().ToUpper());
            Console.ReadLine();
        }
    }
}

输出结果为:

54 00 65 00 73 00 74 00 20 00 6D 00 65 00 73 00 73 00 61 00 67 00 65 00 00 00


0
这是一个经过测试的C#示例,演示了一个以空字符结尾的XML命令,并且运行良好。
strCmd       = @"<?xml version=""1.0"" encoding=""utf-8""?><Command name=""SerialNumber"" />";
sendB        = System.Text.Encoding.UTF8.GetBytes(strCmd+"\0");
sportin.Send = sendB;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接