【问题标题】:Character encoding errors with .NET Core on LinuxLinux 上 .NET Core 的字符编码错误
【发布时间】:2018-12-24 03:46:40
【问题描述】:

这几天让我发疯了,我终于把它归结为一个简单、可重现的问题。

我有一个 NUnit 测试项目,即 .NET Core 2.1。它引用了一个 .NET Standard 2.0 库(我们称之为“Core”)。

在我的测试项目中:

[TestCase(true, false)]
[TestCase(false, false)]
[TestCase(false, true)]
public void ShouldStartWith(bool useInternal, bool passStartsWith)
{
    var result = useInternal ? StartsWithQ("¿Que?") : StringUtilities.StartsWithQ("¿Que?", passStartsWith ? "¿" : null);
    result.ShouldBeTrue();
}

public static bool StartsWithQ(string s)
{
    return _q.Any(q => s.StartsWith(q, StringComparison.InvariantCultureIgnoreCase));
}

Core 项目中的StringUtilities 类中:

public static bool StartsWithQ(string s, string startsWith = null)
{
    return startsWith == null
        ? _q.Any(q => s.StartsWith(q, StringComparison.InvariantCultureIgnoreCase))
        : s.StartsWith(startsWith, StringComparison.InvariantCultureIgnoreCase);
}

两个类都定义了特殊字符列表:

private static readonly List<string> _q = new List<string>
{
    "¡",
    "¿"
};

在 Windows 环境中,所有测试用例都通过。但是当同样的测试在Linux环境下运行时,测试用例ShouldStartWith(False,False)就失败了!

这意味着当测试项目中的所有内容都在运行时,字符串比较工作正常,即使您将特殊字符传递给StringUtilities 方法,比较工作也会正常进行。但是当你比较一个在 Core 项目中编译的字符串时,特殊字符不再是等价的!​​p>

有人知道这是为什么吗?这是一个 .NET 错误吗?如何解决?

【问题讨论】:

  • file 在 Linux 上显示为单元测试和实现的文件类型是什么?在我的机器上,它报告为Program.cs: C++ source, UTF-8 Unicode text 并且测试通过了。
  • @omajid 我不明白这个问题。您能详细说明如何进行您建议的测试吗?
  • 与任何文本文件一样,您必须正确地将字符编码传达给读取它的程序。你的源文件的编码是什么,你告诉编译器什么? UTF-8 将是一个不错的计划。 (file 是一个猜测编码的程序。它在向您显示文件没有您认为的编码方面可能有用,也可能没有用。需要进行一些解释。)
  • @omajid Test.dll: PE32+ executable (console) x86-64 Mono/.Net assembly, for MS Windows Core.dll: PE32 executable (DLL) (console) Intel 80386 Mono/.Net assembly, for MS Windows
  • 你能在源文件上运行文件吗?所有包含倒置问号的文件。另一件要考虑的事情:您可以对这些非 ascii 字符使用 unicode 转义码 (\udddd) 吗?这对测试结果有帮助吗?

标签: c# linux character-encoding .net-core .net-core-2.1


【解决方案1】:

源文件的编码很可能彼此不匹配和/或与编译器设置不匹配。

例子:

包含public void ShouldStartWith(bool useInternal, bool passStartsWith) 的源文件可以使用utf-8 编码,而带有列表的源文件使用Latin-1(或类似的东西)编码。

当我们玩这个时:

  • ¿ 的 utf-8 表示形式为:0xC2 0xBF
  • ¿ 的 Latin-1 表示形式为:0xBF

因此,当编译器将您的源文件解释为 Latin-1 时,他将在 utf-8 保存文件的情况下读取 2 个字节(并且根据 Latin-1 也是 2 个字符),因此无法匹配字符串。

正如 cmets 中所述:克服此问题的最佳方法是将源文件编码为编译器等待的编码。

将操作系统排除为错误源的另一种方法:将已编译的项目(dll 的 - 不要在其他操作系统上重新编译源)从一个操作系统复制到另一个并执行代码。您应该会在具有相同二进制编译器输出的两个操作系统上看到相同的行为。

【讨论】:

  • .Net 使用 UTF-16 来表示字符和字符串。另请参阅 MSDN 上的 Character Encoding in .NET。如果在没有显式转换的情况下使用 UTF-8 或 Latin-1,那么事情就偏题了。
  • 你混淆了源文件中的编码和运行时使用的编码。
猜你喜欢
  • 2021-07-29
  • 2017-09-15
  • 1970-01-01
  • 1970-01-01
  • 2017-11-04
  • 1970-01-01
  • 2021-05-02
  • 1970-01-01
  • 2020-01-19
相关资源
最近更新 更多