为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

PHP
料青山看我应如是 2024-01-20 16:04:40
我正在尝试将一些文件读取为字节并将其与“\u0019\u0093\r\n\u001a\n”进行比较。我确信我总会得到 byte[]{ 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a }。我尝试将这些字节转换为字符串并与字符串进行比较,但总是错误。所以我尝试将字符串转换为字节。但当我比较它们时也总是错误的。(在 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);输出是:False6Byte: 25Byte: 194Byte: 147Byte: 13Byte: 10Byte: 26Byte: 10False比较总是返回 false。我发现从字符串转换为字节后,我又多了一个字节,并且不知道 194 来自哪里。为什么会出现这种情况?我想转换后它们应该是相等的。这是错的吗?如果我想得到我所期望的,我该怎么办?
查看完整描述

1 回答

?
喵喔喔

TA贡献1735条经验 获得超5个赞

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


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


无论如何,此行为与默认编码设置为 UTF8 一致,可能表明它是 Linux 系统(大多数 Windows 系统将使用某些特定于区域设置的代码页作为默认编码,而不是 UTF8)。


如果您希望将原始字节0x93转换为具有基本相同值(即0x0093,又名'\u0093')的 UTF16 字符,那么您需要使用文本编码来解码原始字节,其中代码点0x93实际上转换为 UTF16 代码点0x0093。


幸运的是,有一个网站实际上会告诉我们哪些编码包含该字符,以及它们的值是什么:https ://www.compart.com/en/unicode/charsets/containing/U+0093


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


byte[] bytes = new byte[] { 0x19, 0x93, 0x0d, 0x0a, 0x1a, 0x0a };

string s = "\u0019\u0093\r\n\u001a\n";

Encoding encoding = Encoding.GetEncoding("iso-8859-1");

System.Console.WriteLine(encoding.GetString(bytes) == s);

System.Console.WriteLine(s.Length);

foreach (var b in encoding.GetBytes(s))

{

    System.Console.WriteLine("Byte: " + b);

}

System.Console.WriteLine(encoding.GetString(bytes) == s);

这输出正是你想要的:


True

6

Byte: 25

Byte: 147

Byte: 13

Byte: 10

Byte: 26

Byte: 10

True

显示的字节甚至是bytes数组中的确切字节,我们可以通过将此行添加到程序末尾来演示:


System.Console.WriteLine(encoding.GetBytes(s).SequenceEqual(bytes));

这也将打印True.


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


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


查看完整回答
反对 回复 2024-01-20
  • 1 回答
  • 0 关注
  • 26 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信