【问题标题】:How to output emoji to console in Node.js (on Windows)?如何在 Node.js(在 Windows 上)中将表情符号输出到控制台?
【发布时间】:2017-10-18 16:40:21
【问题描述】:

在 Windows 上,控制台中有一些基本的表情符号支持,因此我可以在键入时获得单色字形,例如????。我可以从 PowerShell 或 C# 控制台应用程序或 Python 输出字符串,它们都可以很好地显示这些字符。

但是,从 Node.js 中,我只能显示几个表情符号(例如 ),但不能显示其他(而不是 ???? 我看到 )。但是,如果我 throw 包含这些字符的字符串,它们会正确显示。

console.log(' ???? ☕ ');
throw ' ???? ☕ ';

如果我运行上面的脚本,输出是

 � ☕

C:\Code\emojitest\emojitest.js:2
throw ' ???? ☕ '; 
^
 ???? ☕

无论如何,我可以正确输出这些表情符号而不会引发错误吗?还是该异常发生在我通过标准 Node.js API 可用的范围之外?

【问题讨论】:

  • 嗯,你比任何人都走得更远。找到支持字形的字体始终是主要障碍。但是 � 是一个编码问题,并非完全不寻常,因为滚动字形位于高位平面中,而咖啡杯则不是。您可能应该关注为什么它在呈现到 stderr 时是可以的,就像在 throw 中一样,而不是到 stdout。
  • @HansPassant 直接写信给stderr 与直接写信给stdout 没有什么不同,可能需要看看 Node.js 是如何处理投掷的……
  • 似乎是 Windows 问题。它在我的 Mac 上运行良好。
  • 现在觉得有点可笑。我刚刚在 Node.js 7.10.0 中尝试了这个示例,它运行良好(我一直在使用最新的 6.x 版本),所以一旦 8.x 发布,这似乎不再是稳定的 Node.js 的问题发布。
  • @bdukes:也许是个愚蠢的问题,但你确定你在完全相同的环境中以完全相同的方式执行完全相同的测试吗?如果是这样,那么我的回答一定是错误的,因为我提到的 libuv 行为在 6.x 和 7.x 之间没有改变。 FWIW 我在 6.x 和 7.x 中得到了相同的结果。

标签: node.js windows unicode console emoji


【解决方案1】:

如果不更改libuv,您想要的可能无法实现。当你(或 控制台)在 Windows 上写入 stdoutstderr 并且流是 TTY, libuv 会自己进行从 UTF-8 到 UTF-16 的转换。在这样做时,它明确 拒绝输出代理对,而是发出替换字符 U+FFFD � 适用于 BMP 之外的任何代码点。

这是uv/src/win/tty.c的罪魁祸首:

  /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
  /* windows console doesn't really support UTF-16, so just emit the */
  /* replacement character. */
  if (utf8_codepoint > 0xffff) {
    utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
  }

throw 消息显示正确,因为 Node 允许 Windows 执行 使用 MultiByteToWideChar() 从 UTF-8 转换为 UTF-16(确实会发出 代理对)在将消息写入控制台之前。 (看 PrintErrorString() in src/node.cc.)

注意:已提交pull request 以解决此问题。

【讨论】:

  • 听起来不错。问题中缺少的细节是OP可能使用Win10。该版本在控制台上进行了大量修补,主要是为了扩展对新 Linux 子系统的支持。
  • 那么,修改后的 libuv(将接受 BMP 之外的代码点并使用 MultiByteToWideChar)可以在 Windows 10 上运行吗? -- 听起来像是一个有效的功能请求:)
  • @Hugues Moreau:我假设修改 libuv 以输出 UTF-16 代理对将允许在支持它们的 Windows 控制台中的节点流中显示非 BMP 字符。不用MultiByteToWideChar(),特别是;删除此处显示的代码行,然后将else 添加到以下块以发出代码点的代理对就足够了。但是我还没有设置 Node.js 的构建环境(或者今天创建一个的时间或倾向!)来尝试它。
  • @Hugues Moreau:是的,确实值得与 libuv 开发人员讨论,看看他们是否会考虑进行修改。我不太了解该库,无法判断引入版本检查或配置标志有多容易,或者这种更改可能会破坏多少兼容性,甚至是它以第一个方式实现的基本原理地点。
【解决方案2】:

(免责声明:我没有解决方案,我使用 Windows 10 上的工具探索了打印表情符号的异常处理有何特别之处——运气好的话可能会安排对这个问题有所了解,也许有人会认识到一些事情并提出解决方案)

看起来 Node 的异常报告代码用于 Windows 调用不同的 Windows API,恰好更好地支持 Unicode。

让我们看看 Node 7.10 源代码:

ReportExceptionAppendExceptionLinePrintErrorString

PrintErrorString,Windows 特定部分detects output type (tty/console or not): - 对于非 tty/console 上下文,它将打印到 stderr(例如,如果您重定向到文件) - 在 cmd 控制台中(没有重定向),它将 convert 文本与 MultiByteToWideChar() 然后 passWriteConsoleW()

如果我使用 ConEmu 运行您的程序(比使用标准 cmd 更容易使用 unicode 和 emoji ——是的,我在这里有点懒惰),我会看到与您看到的类似的东西:console.log 失败打印表情符号,但异常消息中的表情符号打印正常(甚至是滚动字形)。

如果我将所有输出重定向到一个文件(node test.js > out.txt 2>&1,是的,它也适用于 Windows cmd),在这两种情况下我都会得到“干净”的 Unicode。

因此,当程序在 Windows 控制台中打印到 stdoutstderr 时,控制台在打印之前会执行一些(错误的)重新编码工作。当程序直接使用 Windows 控制台 API 时(使用MultiByteToWideChar 自己进行转换,然后使用WriteConsoleW() 写入控制台),控制台会显示光荣的未更改的表情符号。

当 JS 程序使用console API 记录内容时,也许 Node 可以尝试(在 Windows 上)检测控制台并执行与报告异常相同的操作。请参阅 @BrianNixon's answer,它解释了 libuv 中实际发生的情况。

【讨论】:

    【解决方案3】:

    下一个“Windows Terminal”(来自Kayla Cinnamon)和Microsoft/Terminal 项目应该能够显示表情符号。

    这将从 2019 年 6 月开始提供。 通过使用 Consolas 字体,将提供 部分 Unicode 支持。

    Microsoft/Terminal issue 387 中的请求正在进行中。
    Microsoft/Terminal issue 190 正式要求“向 Windows 控制台添加表情符号支持”。

    但仍有问题(2019 年 3 月):

    几天前我将我的 Win10 从 1803 更新到 1809,现在所有字符 >= U+10000(具有 4 个字节或更多字节的 UTF-8)不再显示。
    我也试过最新的 Insider 版本(Windows 10 Insider Preview 18358.1 (19h1_release)),可惜这个bug 还是存在。

    【讨论】:

      猜你喜欢
      • 2011-03-09
      • 2010-10-09
      • 2015-12-31
      • 2012-04-07
      • 2020-04-12
      • 2011-02-20
      • 2014-02-28
      • 2012-07-27
      相关资源
      最近更新 更多