【问题标题】:Text Encoding between Linux and WindowsLinux 和 Windows 之间的文本编码
【发布时间】:2020-03-17 17:06:36
【问题描述】:

我的主要问题是如何让我在 Linux 中拥有的文本文件在 PowerShell 中正确显示。

在 Linux 中,我有一些带有特殊字符的文本文件,实际上记事本显示的文本文件与在 Linux 中显示的完全一样:

不幸的是,我的程序打印到我的 Linux 终端,因此我的 Windows 终端需要相同的输出。我已经看透了其他答案,

  1. 我需要使用 TrueType 字体,所以我使用的是 Lucidia Console
  2. 在我的 Linux 设备上,编码是 UTF-8。根据我在网上找到的每个答案,CHCP 65001 将 PowerShell 中的代码页切换为 UTF-8
  3. Windows Powershell 能够更好地显示内容,因此虽然我尝试使用命令提示符,但我现在正在使用 PowerShell。

使用 CHCP 65001 然后输入

more my_file.txt

显示这个:

使用时

Get-Content -Encoding UTF8 my_file.txt

输出:

这些结果都不够好,但我实际上担心 Get-Content 在这里做了一些不同的事情。我要传输到 Windows 的代码是用 Free Pascal 编写的,在 Free Pascal 中,我可以提供 UTF-8 代码页,仅此而已。因此,虽然 Get-Content 对我来说是一个很好的命令来检查 PowerShell 是否能够产生所需的输出,但对我来说使用它是不切实际的。在 Pascal 中,输出(写入 PowerShell 显示)显示为:

这也不好,这些行应该连接,因为它们在 Linux 中会连接(显然有些字符被解释为?)。但是,这可能是 Pascal 中选择的代码页的问题,这将是下一步。

我现在的问题是,如何让 Windows Powershell 默认显示一个文本文件,如记事本版本中所示。在我的代码中到处运行 Get-Content 对我来说是不切实际的,因此尽管结果看起来更有希望,但我不能遵循这一点。

作为一个后续问题,因为我在网上的任何地方都找不到它,所以这里显示内容的主要参与者是什么,因为它显然是一个比编码更大的故事。为什么“更多”和“获取内容”命令显示不同的输出?为什么“获取内容”不能读取所有内容?我曾假设 UTF-8 是一个通用标准,可以读取 UTF-8 的程序至少可以实际读取所有字符,但它们的读取方式都不同。

作为文本的输入是:

    ╭─────╮
    │     │
  ╭─│───╮ │
  │ │   │ │
  │ │ ╭─│───╮
  │ │ │ │ │ │
╭─│───│─╯ │ │
│ │ │ │   │ │
│ │ ╰─╯   │ │
│ │       │ │
│ ╰───────│─╯
│         │
╰─────────╯

响应下面发布的答案,我可以看到

more my_file.txt

生产

使用时

$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = 
  New-Object System.Text.UTF8Encoding 

【问题讨论】:

  • @AdminOfThings 结果与 Get-Content 输出相同。
  • 所以我看到gc $file -Encoding UTF8 正在获取发布到您帖子中的字符。我还看到 AdminOfThings 发布的 ReadAllText .net 函数具有相同的结果。它似乎正确地获取了内容。

标签: linux powershell encoding decoding


【解决方案1】:
  • 确保您的 UTF-8 编码文本文件具有 BOM - 否则,您的文件将被 Windows PowerShell 误解为基于系统的活动 ANSI 代码页进行编码(幸运的是,PowerShell [Core] 6+ 现在在没有 BOM 的情况下始终默认为 UTF-8)。

    • 或者,使用Get-Content -Encoding Utf8 my_file.txt 明确指定文件的编码。

    • 有关 Windows PowerShell 与 PowerShell [Core] 中字符编码的全面讨论,请参阅this answer

  • 为了外部程序的输出被正确地捕获到变量中正确地重定向到文件您需要将[Console]::OutputEncoding 设置为给定程序在输出时使用的字符编码(不过,打印到显示器这可能不是必需的):

    • 如果代码页 65001 (UTF-8) 有效并且您的程序尊重这一点,您需要设置 [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding;请参阅下文,了解如何确保 65001 真正生效,因为在 PowerShell 中运行chcp 65001 有效的。

    • 你提到了 FreePascal,它的 Unicode 支持被描述为 here
      但是,您的屏幕截图暗示您的 FreePascal 程序的输出不是 UTF-8,因为圆角字符已转码为 ? 字符(这表明对系统的 OEM 代码页进行了有损转码,这些字符不存在的地方)。

    • 因此,为了解决您的问题您必须确保您的 FreePascal 程序无条件输出 UTF-8 或尊重活动代码页(由chcp 报告),假设您首先将其设置为65001(UTF-8 代码页;见下文)。

  • 在控制台窗口中选择可以呈现圆角 Unicode 字符的字体(例如 (U+256D);Windows PowerShell 默认字体 Lucinda Console ,可以(它呈现,如您的问题所示),但是Consolas,例如(PowerShell [Core] 6+ 默认使用),可以 em>.


始终使用 UTF-8 编码与外部程序

注意

  • 下面的命令对于Get-Content cmdlet 等PowerShell 命令既没有必要也没有任何影响。

  • 一些旧版控制台应用程序 - 特别是 more.com(Windows PowerShell 封装在 more 函数中) - 基本上不支持 Unicode ,仅限旧版 OEM 代码页。[*]

根据我在网上可以找到的所有答案,CHCP 65001 将 PowerShell 中的代码页切换为 UTF-8

chcp 65001 如果从 PowerShell 中 运行,不起作用,因为 .NET 缓存 @987654345 @ PowerShell 会话启动时的值,以及当时有效的代码页。

相反,您可以使用以下内容来完全识别控制台窗口 UTF-8(这也隐含地使 chcp 报告 65001 之后):

$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding =
                    New-Object System.Text.UTF8Encoding

这使得 PowerShell 将外部程序的输出解释为 UTF-8,并将其发送外部程序的数据编码为 UTF-8(感谢首选项变量 $OutputEncoding)。

请参阅this answer 了解更多信息。


[*] 当 UTF-8 代码页 65001 生效时,more 悄悄地跳过包含至少一个无法映射到系统 OEM 的 Unicode 字符的行代码页(系统的单字节 OEM 代码页中不存在的任何字符,只能表示 256 个字符),在这种情况下适用于包含圆角字符的行,例如 (BOX DRAWINGS LIGHT ARC上下左右,U+256D)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-20
    • 2010-10-29
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多