Как выводить emoji на консоль в Node.js (в Windows)?

В Windows есть некоторые основные поддержки emoji в консоли, так что я могу получить монохромный глиф, если я , например, или 📜. Я могу вывести строку из PowerShell или консольного приложения С# или Python, и все они достаточно хорошо отображают эти символы.

Однако, из Node.js, я могу получить только пару emoji для отображения (например, ), но не другие (вместо 📜 я вижу ). Однако, если я throw строку с этими символами, они отображаются правильно.

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

Если я запустил вышеприведенный скрипт, вывод будет

 � ☕

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

Есть ли в любом случае, что я могу правильно выводить эти emojis, не выдавая ошибки? Или это исключение происходит за пределами того, что доступно мне через стандартные API Node.js?

Ответы

Ответ 1

То, что вы хотите, может быть невозможно без изменения libuv. Когда вы (или консоль) записываете в stdout или stderr в Windows, а поток - TTY, libuv выполняет собственное преобразование с UTF-8 на UTF-16. При этом он явно отказывается выводить суррогатные пары, вместо этого U+FFFD символ U+FFFD для любого U+FFFD за пределами BMP.

Heres виновник в 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 выполнять преобразование из UTF-8 в UTF-16 с помощью MultiByteToWideChar() (который испускает суррогатные пары) перед записью сообщения на консоль. (См. PrintErrorString() в src/node.cc.)

Ответ 2

(Отказ от ответственности: у меня нет решения, я изучил, что делает специальную обработку исключений применительно к печати emoji, с инструментами, которые у меня есть на Windows 10 - С некоторой удачей, которая может немного рассказать о проблеме, и, возможно, кто-то будет признать что-то и придумать решение)

Похоже, что код отчетов об исключениях для узлов для Windows вызывает другой API Windows, который, оказывается, лучше поддерживает Unicode.

Давайте посмотрим с помощью источников Node 7.10:

ReportExceptionAppendExceptionLinePrintErrorString

В PrintErrorString раздел, PrintErrorString Windows, определяет тип вывода (tty/console или нет): - для контекста non-tty/console он будет печатать на stderr (например, если вы перенаправляетесь на файл) - в консоли cmd (без перенаправления), он преобразует текст с помощью MultiByteToWideChar() а затем передаст это WriteConsoleW().

Если я запустил вашу программу с помощью ConEmu (проще, чем получить стандартное cmd для работы с unicode и emoji - да, я немного здесь ленился), я вижу нечто похожее на то, что вы видели: console.log не печатает emoji, но emoji в сообщении об исключении печатаются ОК (даже глиф прокрутки).

Если я перенаправляю весь вывод в файл (node test.js > out.txt 2>&1, да, это тоже работает в Windows cmd), я получаю "чистый" Unicode в обоих случаях.

Так что, когда программа печатает на stdout или stderr в консоли Windows, консоль выполняет некоторую (плохую) перекодировку перед печатью. Когда программа напрямую использует консольный API Windows (выполнение самого преобразования с помощью MultiByteToWideChar затем запись на консоль с помощью WriteConsoleW()), консоль показывает славные неизмененные эможи.

Когда JS-программа использует console API для записи материала, возможно, Node может попробовать (в Windows) обнаружить консоль и сделать то же самое, что и для отчетов об исключениях. См. Ответ @BrianNixon, в котором объясняется, что на самом деле происходит в libuv.

Ответ 3

Следующий " Терминал Windows " (от Кайлы Синнамон) и проект Microsoft/Terminal должны отображать смайлики.

Это будет доступно с июня 2019 года. Благодаря использованию шрифта Consolas будет обеспечена частичная поддержка Unicode.

Запрос находится в процессе выполнения в Microsoft/Terminal 387.
А выпуск Microsoft/Terminal 190 формально требует "добавить поддержку emoji в консоль Windows".

Но есть еще проблемы (март 2019):

Я обновил свой Win10 с 1803 до 1809 несколько дней назад, и теперь все символы> = U + 10000 (UTF-8 с 4 байтами или более) больше не отображаются.
Я также попробовал новейшую инсайдерскую версию (Windows 10 Insider Preview 18358.1 (19h1_release)), к сожалению, эта ошибка все еще существует.