从 xml 文件读取字符时控制台打印错误字符

Console print wrong character when read character from xml file

我想解析 xml 文件以打印字符控制台或 winforms。看起来像这样,

<?xml version="1.0" encoding="UTF-8"?>
<kanjidic2>
<header>
  <file_version>4</file_version>
  <database_version>2015-093</database_version>
  <date_of_creation>2015-04-03</date_of_creation>
</header>
<character>
  <literal>亜</literal>
  <codepoint>
    <cp_value cp_type="ucs">4e9c</cp_value>
    <cp_value cp_type="jis208">16-01</cp_value>
  </codepoint>
</character>
<character>
  <literal>唖</literal>
  <codepoint>
    <cp_value cp_type="ucs">5516</cp_value>
    <cp_value cp_type="jis208">16-2</cp_value>
  </codepoint>
</character>

...
</kanjidic2>

literal 标签中的字符是要打印的字符。字符本身是用 UTF8 编码的(提供者说)。 我使用这段代码在控制台中解析和打印它。

class Program
{
    static void Main(string[] args)
    {
        Console.OutputEncoding = Encoding.UTF8;

        foreach (Kanji kanji in Parse())
        {
            Console.WriteLine(kanji.Character);
        }

        Console.ReadKey();
    }

    private static IEnumerable<Kanji> Parse()
    {
        var doc = new XmlDocument();
        doc.Load("kanjidic2.xml");

        XmlNodeList nodes = doc.DocumentElement.SelectNodes("/kanjidic2/character");

        foreach (XmlNode node in nodes)
        {
            yield return new Kanji { Character = node.SelectSingleNode("literal").InnerText };
        }
    }
}

public class Kanji
{
    public string Character { get; set; }
}

当我 运行 编程时,它开始打印字符,但它不是我在 literal 中看到的字符(我认为 none 可以读取它)。 我尝试将控制台输出编码更改为 Unicode 这次它可以正确打印字符。

问题是为什么当我设置输出编码为UTF8时控制台不能正确打印字符?

是否因为它读取以 UTF8 编码的字符并将该字符作为 Unicode 存储在内存中(这意味着在 .net 中为 UTF16?)?如果是这样,为什么它不能像我第一次设置的那样将字符转换回 UTF8。

尝试以 UTF8 字节加载 xml,然后加载 xml 文件:

 byte[] encodedString = Encoding.UTF8.GetBytes(xmlString);
using (MemoryStream ms = new MemoryStream(encodedString))
{
    ms.Flush();
    ms.Position = 0;
   XmlDocument xmlDoc = new XmlDocument();
   xmlDoc.Load(ms);
}

如果您有一个文件而不是 xml 字符串,只需首先加载为这样的常规文件

 var xmlString= File.ReadAllText(FilePath,Encoding.Default)

您可能会在这里遇到几个潜在的问题。

  1. 控制台在显示其他字符集(例如汉字)时出现问题,无需额外的工作或代码。你可以试试 changing the Console font to a TrueType font such as Consolas or Courier New. Or for UTF-32, look at the code samples here.
  2. 您的 xml 文件是没有 BOM 的 UTF8,如果这是静态的(不会更改),那么您最好在代码中指定它。您的 gist is using Encoding.Default but when I changed it to Encoding.UTF8 the Kanji string was correct. I looked at methods for detecting the encoding,但您需要决定 XML 文件是否会更改编码。
  3. 我在十六进制编辑器中查看了第一个<literal>亜</literal>,它是E4 BA 9C,但是当我将字符粘贴到Visual Studio时,它只是E4 9C。我相信 BAcombining character。如果编码错误,您可能会看到 亜。如果你没有使用 TTF 字体,你会看到疯狂的字符。即使在我的系统上使用 Consolas,E4 9C 字符串显示一个带框的问号,但当我复制并粘贴时它是正确的字符。