C# 如何正确比较字符串和字节?

C# 如何正确比较字符串和字节?,c#,.net,string,encoding,byte,C#,.net,String,Encoding,Byte,我正在尝试以字节形式读取一些文件,并将其与“\u0019\u0093\r\n\u001a\n”进行比较。我确定我总是得到字节[]{0x19,0x93,0x0d,0x0a,0x1a,0x0a} 我尝试将这些字节转换为字符串并与字符串进行比较,但始终为false 所以我尝试将字符串转换为字节。但当我比较它们时,也总是错误的 (在Windows 10上使用.NET Core 3.0) 我尝试了以下代码 byte[] bytes = new byte[]{ 0x19, 0x93, 0x0d, 0x0a,

我正在尝试以字节形式读取一些文件,并将其与“\u0019\u0093\r\n\u001a\n”进行比较。我确定我总是得到字节[]{0x19,0x93,0x0d,0x0a,0x1a,0x0a}

我尝试将这些字节转换为字符串并与字符串进行比较,但始终为false

所以我尝试将字符串转换为字节。但当我比较它们时,也总是错误的

(在Windows 10上使用.NET Core 3.0)

我尝试了以下代码

byte[] bytes = new byte[]{ 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a };
string s = "\u0019\u0093\r\n\u001a\n";
System.Console.WriteLine(Encoding.Default.GetString(bytes) == s);
System.Console.WriteLine(s.Length);
foreach (var b in Encoding.Default.GetBytes(s))
{
    System.Console.WriteLine("Byte: "+b);
}
System.Console.WriteLine(Encoding.Default.GetString(bytes) == s);
输出为:

False
6
Byte: 25
Byte: 194
Byte: 147
Byte: 13
Byte: 10
Byte: 26
Byte: 10
False
比较总是返回false。我发现在从字符串到字节的转换之后,我又多了一个字节,不知道194是从哪里来的。为什么会发生这种情况

我想它们在转换后应该是相等的。错了吗


如果我想得到我想要的,我应该怎么做?

在原始编码字节中,出现问题的字符代码是
0x0093

您遇到的问题是,在系统上的
默认编码中(在Windows上,系统的当前代码页是什么),编码为
0x0093
的字符无法识别。因此,当您尝试对其进行解码时,会得到UTF16字符点
0xfffd
(这是.NET解码器对无法识别字符的默认设置)。然后将其重新编码为默认编码,即
0x93c2
(您在输出中看到的字节序列,以十进制表示,即
194
,后跟
147

值得一提的是,此行为与默认编码设置为UTF8一致,这可能表明它是Linux系统(大多数Windows系统将使用特定于语言环境的代码页作为默认编码,而不是UTF8)

如果要将原始字节
0x93
转换为具有基本相同值的UTF16字符(即
0x0093
,又称
'\u0093'
),然后需要使用文本编码对原始字节进行解码,其中代码点
0x93
实际上转换为UTF16代码点
0x0093

幸运的是,有一个网站会告诉我们哪些编码包含这个字符,以及它们的价值是什么:

从该表中,我们可以看到大量的编码(也有一些编码,其中UTF16字符
'\u0093'
被编码为不同的值,即
0x33
…显然,我们不需要这些编码)。列表中的第一个编码“ISO-8859-1”看起来很合适,所以让我们尝试使用它来解码您的字节:

byte[]bytes=新字节[]{0x19、0x93、0x0d、0x0a、0x1a、0x0a};
字符串s=“\u0019\u0093\r\n\u001a\n”;
Encoding Encoding=Encoding.GetEncoding(“iso-8859-1”);
System.Console.WriteLine(encoding.GetString(字节)=s);
系统控制台写入线(s长度);
foreach(编码中的var b.GetBytes)
{
系统控制台写入线(“字节:+b”);
}
System.Console.WriteLine(encoding.GetString(字节)=s);
这会输出您想要的内容:

True 6 Byte: 25 Byte: 147 Byte: 13 Byte: 10 Byte: 26 Byte: 10 True 这也将打印
True

这个故事的寓意是:知道您试图解码的字节的原始编码不是可选的。您必须确切地知道使用了哪种编码,因为它只是一种编码。如果您使用了错误的编码,那么您也可以尝试解码加密数据


根据定义,不同的文本编码是不同的。这意味着一种编码中的字节与另一种编码中的字节完全不同(有点……大多数编码在最低的128个代码点上重叠,因为它们都基于ASCII)。如果您使用错误的编码对某些字节进行解码(或者,在本例中,解码器将无法识别字符并将其转换为表示无法识别字符的占位符),您只会得到随机结果。

在Unicode时代,Unicode字符串可以通过多种方式编码为字节:|即使在Unicode字符串中,规范化也会成为一个问题,因为同一个字符可以通过不同的代码点进行预演:文件似乎是一个字节的数据,而不是Unicode,后者是两个字节的数据。那么,为什么要尝试比较一个单字节数据和两字节数据的文件呢?字符是一个类,其值为两个字节,私有属性表示字符为一个或两个字节。当您使用\u0019时,您正在将私有属性设置为两个字节。@jdweng Hi谢谢您的回复。我试图读取的文件基本上是一个二进制文件。这些字节位于头部分内,通常是不变的。有些字节实际上代表一些单词,所以我只是将正确的值存储为字符串,并通过比较字节和字符串来验证文件的格式是否正确。所以我想这是个坏主意,我必须比较字节值?文件在实际二进制之前有一个文本头。如果用记事本打开图像文件,您将看到类似的标题。通常是一个固定字符(起始字符),用于分隔标题。现在我不知道你为什么在没有unicode的情况下试图与unicode字符串进行比较。你可以安全地忽略关于文件有“文本头”的注释。大多数文本文件没有表示编码的标题。唯一的例外是XML或HTML之类的东西,其中包括一个说明所用编码的ASCII头,以及一些可选的UTF8和UTF16文件,这些文件有时以表示编码的字节序列开头(搜索“Unicode字节顺序标记”)…请注意,只有对于UTF16,双字节序列才表示字节顺序;对于UTF8,序列是三个字节,并且由于UTF8只有一个可能的字节顺序,因此它始终是相同的三个字节)
System.Console.WriteLine(encoding.GetBytes(s).SequenceEqual(bytes));