【问题标题】:How do I ignore the UTF-8 Byte Order Marker in String comparisons?如何在字符串比较中忽略 UTF-8 字节顺序标记?
【发布时间】:2011-02-24 07:17:16
【问题描述】:

我在使用 Visual Studio 2010 在 C# 4.0 中比较单元测试中的字符串时遇到问题。同样的测试用例在 Visual Studio 2008(使用 C# 3.5)中正常工作。

下面是相关代码sn-p:

byte[] rawData = GetData();
string data = Encoding.UTF8.GetString(rawData);

Assert.AreEqual("Constant", data, false, CultureInfo.InvariantCulture);

在调试此测试时,data 字符串在肉眼看来包含与文字完全相同的字符串。当我调用data.ToCharArray() 时,我注意到字符串data 的第一个字节是值65279,它是UTF-8 字节顺序标记。我不明白为什么Encoding.UTF8.GetString() 保留这个字节。

如何让Encoding.UTF8.GetString()将字节顺序标记放入结果字符串中?

更新: 问题在于从磁盘读取文件的GetData() 使用FileStream.readbytes() 从文件中读取数据。我通过使用StreamReader 纠正了这个问题,并使用Encoding.UTF8.GetBytes() 将字符串转换为字节,这是它最初应该做的!感谢大家的帮助。

【问题讨论】:

  • 你能发布一个小而完整的程序来演示这个问题吗?

标签: c# unit-testing visual-studio-2010 utf-8 equality


【解决方案1】:

好吧,我认为这是因为原始二进制数据包含 BOM。如果您不想要它,您可以在解码后自己删除 BOM - 但您应该考虑字节数组是否应该考虑 BOM 开始。

编辑:或者,您可以使用StreamReader 来执行解码。这是一个示例,显示相同的字节数组使用Encoding.GetString 转换为两个字符或通过StreamReader 转换为一个字符:

using System;
using System.IO;
using System.Text;

class Test
{
    static void Main()
    {
        byte[] withBom = { 0xef, 0xbb, 0xbf, 0x41 };
        string viaEncoding = Encoding.UTF8.GetString(withBom);
        Console.WriteLine(viaEncoding.Length);

        string viaStreamReader;
        using (StreamReader reader = new StreamReader
               (new MemoryStream(withBom), Encoding.UTF8))
        {
            viaStreamReader = reader.ReadToEnd();           
        }
        Console.WriteLine(viaStreamReader.Length);
    }
}

【讨论】:

  • 您说得对,原始数据包括 BOM。它不应该,所以我正在修复那部分。一个哲学后续问题:为什么String.Equals 方法会考虑BOM?为什么在进行字符串比较时不将其简单地忽略或将其视为元数据而不是字符串的“肉”?
  • @Skrud:你有不同的字符序列。原始 String.Equals 方法比较序数序列,无需进一步考虑。其他一些可用的字符串比较(文化感知等)可能会忽略 BOM - 我不确定。鉴于它在某些方面是一个奇怪的角色,我真的不相信任意忽略它是合适的。这么说吧:等式失败表明您有一些错误的数据,因此该行为导致您改进了代码。这是一件好事,不是吗?
  • 绝对。这首先是测试的重点。 :-)
【解决方案2】:

有一种比创建 StreamReader 和 MemoryStream 更有效的方法:

1) 如果你知道总有一个 BOM

string viaEncoding = Encoding.UTF8.GetString(withBom, 3, withBom.Length - 3);

2) 如果您不知道,请检查:

string viaEncoding;
if (withBom.Length >= 3 && withBom[0] == 0xEF && withBom[1] == 0xBB && withBom[2] == 0xBF)
    viaEncoding = Encoding.UTF8.GetString(withBom, 3, withBom.Length - 3);
else
    viaEncoding = Encoding.UTF8.GetString(withBom);

【讨论】:

    【解决方案3】:

    如果你 Trim() 解码的字符串,我相信多余的字符会被删除

    【讨论】:

      猜你喜欢
      • 2011-07-13
      • 1970-01-01
      • 2013-06-03
      • 2013-01-17
      • 2020-05-29
      • 2019-09-17
      • 1970-01-01
      相关资源
      最近更新 更多