14

编辑:我最初认为这与 .NET Framework 4.5 有关。原来它也适用于 .NET Framework 4.0。

Windows Server 2012 中字符串的处理方式发生了变化,我试图更好地理解这一点。StartsWith 的行为似乎发生了变化。使用 .NET Framework 4.0 和 4.5 可以重现该问题。

在 Windows 7 上使用 .NET Framework 4.5,下面的程序会打印“False, t”。在 Windows 2012 Server 上,它改为打印“True, t”。

internal class Program
{
   private static void Main(string[] args)
   {
      string byteOrderMark = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
      Console.WriteLine("test".StartsWith(byteOrderMark));
      Console.WriteLine("test"[0]);
   }
}

换句话说,无论字符串内容如何,​​StartsWith(ByteOrderMark) 都会返回 true。如果您的代码尝试使用以下方法去除字节顺序标记,则此代码在 Windows 7 上可以正常工作,但在 Windows 2012 上将打印“est”。

internal class Program
{
  private static void Main(string[] args)
  {
     string byteOrderMark = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
     string someString = "Test";

     if (someString.StartsWith(byteOrderMark))
        someString = someString.Substring(1);

     Console.WriteLine("{0}", someString);
     Console.ReadKey();

  }

}

我意识到如果您在字符串中有字节顺序标记,那么您已经做错了,但是我们正在与具有此功能的遗留代码集成。我知道我可以通过执行以下操作来解决这个特定问题,但我想更好地理解这个问题。

someString = someString.Trim(byteOrderMark[0]);

Hans Passsant 建议使用 UTF8Encoding 的构造函数,它可以让我明确告诉它发出 UTF8 标识符。我试过这个,但它给出了相同的结果。下面的代码在 Windows 7 和 Windows Server 2012 之间的输出不同。在 Windows 7 上,它打印“结果:假”。在 Windows Server 2012 上,它会打印“结果:真”。

  private static void Main(string[] args)
  {
     var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
     string byteOrderMark = encoding.GetString(encoding.GetPreamble());
     Console.WriteLine("Result: " + "Hello".StartsWith(byteOrderMark));
     Console.ReadKey();
  }

我还尝试了以下变体,它在 Windows 7 上打印 False、False、False,但在 Windows Server 2012 上打印 True、True、False,这证实它与 Windows Server 2012 上的 StartsWith 实现有关。

  private static void Main(string[] args)
  {
     var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
     string byteOrderMark = encoding.GetString(encoding.GetPreamble());
     Console.WriteLine("Hello".StartsWith(byteOrderMark));
     Console.WriteLine("Hello".StartsWith('\ufeff'.ToString()));
     Console.WriteLine("Hello"[0] == '\ufeff');

     Console.ReadKey();
  }
4

1 回答 1

15

结果我可以重现这个,在 Windows 8.1 上运行测试程序。它与 Server 2012 属于同一个“家族”。

问题的最可能根源是文化敏感比较规则已更改。它们可能是,呃,片状的,并且会对这些角色产生奇怪的结果。BOM 是一个零宽度空间。推理出这一点需要与理解为什么 "abc".StartsWith("") 返回 true 相同的心理体操 :)

您需要使用 StringComparison.Ordinal 来解决您的问题。这产生了假,假,假:

private static void Main(string[] args) {
    var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: true);
    string byteOrderMark = encoding.GetString(encoding.GetPreamble());
    Console.WriteLine("Hello".StartsWith(byteOrderMark, StringComparison.Ordinal));
    Console.WriteLine("Hello".StartsWith("\ufeff", StringComparison.Ordinal));
    Console.WriteLine("Hello"[0] == '\ufeff');
    Console.ReadKey();
}
于 2013-10-21T13:31:49.793 回答