在Windows Server 2012中启动更改

Nit*_*amk 13 c# string unicode .net-4.5

编辑:我原本以为这与.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]);
   }
}
Run Code Online (Sandbox Code Playgroud)

换句话说,无论字符串内容如何,​​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();

  }
Run Code Online (Sandbox Code Playgroud)

}

我意识到如果你在字符串中有字节顺序标记,你已经做错了,但我们正在与具有此功能的遗留代码集成.我知道我可以通过以下方式解决这个具体问题,但我想更好地理解这个问题.

someString = someString.Trim(byteOrderMark[0]);
Run Code Online (Sandbox Code Playgroud)

Hans Passsant建议使用UTF8Encoding的构造函数,它允许我明确地告诉它发出UTF8标识符.我尝试了这个,但它给出了相同的结果.以下代码在Windows 7和Windows Server 2012之间的输出方面有所不同.在Windows 7上,它打印"Result:False".在Windows Server 2012上,它打印"Result:True".

  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();
  }
Run Code Online (Sandbox Code Playgroud)

我还尝试了以下变体,它在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();
  }
Run Code Online (Sandbox Code Playgroud)

Han*_*ant 13

原来我可以重复这一点,在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();
}
Run Code Online (Sandbox Code Playgroud)