UTF-8 字节标记检查根据操作系统给出不同的值

UTF-8 Byte Mark check gives different value based on operating system

我们有一些单元测试会在将 XML 字符串加载到 XmlDocument 之前检查其 UTF-8 字节标记。使用 Windows 7 64 位一切正常,但我们注意到在 Windows 10 64 位下尝试 运行 时有一堆测试失败。

经过一些调查,我们发现 Windows 10 上的 XML 字符串正在被 p运行ed(前导码存在),而 Windows 7 它没有。

这是代码片段:

 public static string PruneUtf8ByteMark(string xmlString)
    {
        var byteOrderMarking = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
        if (xmlString.StartsWith(byteOrderMarking))
        {
            xmlString = xmlString.Remove(0, byteOrderMarking.Length);
        }

        return xmlString;
    }

StartsWith 为 Windows 10 返回 true,为 Windows 7 返回 false . 请注意,使用的是相同的 XML 字符串,这里唯一的区别是 OS.

有什么想法吗?我们在这里有点迷路,因为两台 PC 都是 x64 运行使用相同的 .NET 版本。

编辑: 该字符串来自 class via:

public static string XmlString = "<?xml version=\"1.0\"....

在 Windows 10 上,小于号被 t运行 处理,因为字节标记检查为真。

问题是由文化敏感比较引起的。

byteOrderMarking 不是可见字符,因此在比较期间将被剪裁。

见以下案例:

"".StartsWith("") // = true
"aa".StartsWith("") // = true 
"aa".StartsWith("", StringComparison.Ordinal) // = true

所以每个字符串都以空字符串开头。现在有了 byteOrderMarking :

var byteOrderMarking = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
byteOrderMarking.Equals("") // = False
byteOrderMarking.Equals("", StringComparison.CurrentCulture) // = True
byteOrderMarking.Equals("", StringComparison.Ordinal) // = False

现在我们可以看到byteOrderMarking 等于一个空字符串只有与Current culture 比较。当您尝试检查是否是一个以 byteOrderMarking 开头的字符串时,它就像是与一个空字符串进行比较。

Ordinal 和 CurrentCulture 之间的区别在于,第一个是字节到字节的比较,而第二个将根据文化进行规范化。

最后,我建议始终使用 Ordinal(或 OrdinalIgnoreCase)来比较技术字符串。