【问题标题】:Problems with UTF8 text in XE7 ReadLn commandXE7 ReadLn 命令中的 UTF8 文本问题
【发布时间】:2015-08-22 22:01:39
【问题描述】:

尝试在 Delphi XE7 控制台应用程序中显示 UTF 8 文本时,我遇到了一个愚蠢但令人讨厌的情况。 似乎 ReadLn 命令在第二次尝试后才读取正确的 UTF 8 字符。例如:

    program ConsTest;

    {$APPTYPE CONSOLE}

    {$R *.res}

    uses
      System.SysUtils,
      System.Classes,
      WinApi.Windows;

    var
      CurrentCodePage: Integer;
      Command: String;
      Running: Boolean;
      MyText: String;

    begin
      CurrentCodePage := GetConsoleOutputCP;
      SetConsoleOutputCP(CP_UTF8);
      SetTextCodePage(Output, CP_UTF8);

      MyText := 'Olá mundo.';
      WriteLn(MyText);

      Running := True;
      while Running do
      begin
        ReadLn(Command);
        WriteLn(Command);
        if (Command = '/q') then
          Running := false;
      end;

      SetConsoleOutputCP(CurrentCodePage);
      SetTextCodePage(Output, CurrentCodePage);
    end.

在上面的示例中,在我运行应用程序之后,如果我输入以下文本:

'Olá mundo.'

WriteLn 将显示:

'老世界。'

在第一遍之后,ReadLn 命令读取的所有 UTF-8 字符都显示正常。 这段代码有问题吗?我试图在网上搜索更多细节,但我没有找到任何与此相关的信息。 调用“WriteLn(MyText);”在代码的开头,显示文本“Olá mundo”。正确。

【问题讨论】:

  • 在将 windows 控制台切换为 UTF8 后,您可以关闭并重置输入文件吗?读/写有自己的内部缓冲区,在切换代码页之前可能会预先填充并预先转换为 UCS-2
  • 我也认为SetTextCodePage 应该在InputOutput 上调用,实际上这可能比CloseFile/Reset 优于Input 更好或更糟
  • 我认为@TLama 指向SetConcoleCP 函数msdn.microsoft.com/ru-ru/library/windows/desktop/ms686013.aspx 是正确的-但是它是否适用于UTF-8 以及哪些Windows 版本需要反复试验:@987654323 @ OTOH 有 MSYS、4NT/TakeW32、Cygwin 等替代控制台,也许还有 PowerShell...
  • @Arioch 使用与示例相同的代码,如果我尝试您建议的测试(如果 MyText=Command 然后 writeln ('yes') else writeln('no');)。它在第一遍评估为假,在所有后续遍中评估为真。如果我将输入代码页更改为 UTF8,它总是会失败。

标签: delphi utf-8 console console-application windows-console


【解决方案1】:

好的,在对 Arioch 的第一条评论多加注意之后,我尝试了下面的代码,它可以在任何控制台上完美运行。


    program ConsTest;

    {$APPTYPE CONSOLE}

    {$R *.res}

    uses
      System.SysUtils,
      System.Classes,
      WinApi.Windows;

    var
      Command: String;
      Running: Boolean;
      MyText: String;

    begin
      MyText := 'Olá mundo.';
      WriteLn(MyText);

      Reset(Input); //*** That's the catch. ***

      Running := True;
      while Running do
      begin
        ReadLn(Input, Command);
        if (MyText = Command) then
          WriteLn('Yes')
        else
          WriteLn('No');

        WriteLn(Command);
        if (Command = '/q') then
          Running := false;
      end;
    end.

*OBS:上面的代码不适用于某些字母,我需要更好地了解 Unicode 和 Delphi 中的控制台模式。 由于某些巧合,它解决了我的问题,但实际上不能被视为答案。无论如何,调用“Reset(Input)”函数似乎是必要的,以确保第一次调用 ReadLn 能够正常工作。

【讨论】:

  • 您的问题是关于 Unicode,特别是 UTF-8。我感到困惑。
  • @Arioch。实际上,“不当行为”只是在 Windows 控制台下。它总是在 Cygwin 上工作。我习惯于使用 PHP 开发 Web 应用程序,在该语言中,我必须将代码集更改为 UTF8 才能在 Web 浏览器上正确显示葡萄牙语字符。直到在这篇文章之后我才意识到 XE7 字符串类型默认是 UNICODE 并且没有必要更改控制台输入/输出的任何内容,“mea culpa, mea maxima culpa”,我真的很抱歉。感谢您的支持。
  • 好吧,一旦您离开 ANSI 代码页,您就会遇到麻烦。 Delphi Writeln/Readln 不支持 Unicode。在我看来,这个答案与您提出的问题不符。
  • @David Ok David,请原谅我的无知,但我需要更多关于这个的信息。当我遇到上面描述的问题时,我认为这是由于我的程序和 Windows 控制台代码页之间的一些错误配置而发生的。 ->
  • @David 然后,我发现在 XE7 中,字符串类型实际上是 UnicodeString 的别名,我的理解是 XE7 已经在处理扩展的葡萄牙语字符,如 áéíóúãõàçÇÁÉÍÓÚ...不得不担心它。实际上,我作为答案发布的代码在 Windows 控制台和 Cygwin 下对于我必须处理的任何这些扩展字符都可以正常工作,而且我不必对 Windows 控制台配置进行任何更改。 ->
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多