2017-05-18 52 views
8

W systemie Windows istnieje kilka podstawowych funkcji obsługi emoji w konsoli, dzięki czemu mogę uzyskać monochromatyczny glif, jeśli wpiszę, np. lub . Mogę wyprowadzić ciąg z PowerShell lub aplikacji konsoli C# lub Python i wszystkie one dobrze pokazują te znaki.Jak wyprowadzać emoji na konsolę w Node.js (w systemie Windows)?

Jednak z node.js, mogę tylko kilka emotikonów do wyświetlania (np ), ale nie inne (zamiast widzę ). Jednak jeśli I throw ciąg znaków z tymi znakami, wyświetlają się poprawnie.

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

Jeśli uruchomić powyższy skrypt, wyjście jest

� ☕ 

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

Czy mimo to mogę wyjście te emotikony poprawnie bez rzuca błąd? Czy ten wyjątek ma miejsce poza tym, co jest dostępne dla mnie za pośrednictwem standardowych interfejsów API Node.js?

+2

Hmm, masz dużo więcej niż ktokolwiek inny. Znalezienie czcionki obsługującej glify jest niezmiennie główną przeszkodą. Ale to problem kodowania, nie całkiem niezwykły, ponieważ glify przewijania znajdują się w płaszczyznach bitów górnych, a filiżanka kawy nie. Prawdopodobnie powinieneś się skupić na tym, dlaczego jest w porządku, gdy jest renderowany na stderr, tak jak to będzie w "rzucie", ale nie na standardowe wyjście. –

+0

@HansPassant pisząc bezpośrednio do 'stderr' nie robi niczego innego niż pisanie bezpośrednio na' stdout', prawdopodobnie trzeba zajrzeć do tego, jak Node.js obsługuje rzutowanie ... – bdukes

+0

Wydaje się, że problem dotyczy Windows. Działa dobrze na moim macu. – hasen

Odpowiedz

6

Co chcesz, może nie być możliwe bez zmiany na libuv. Kiedy (lub konsola) napisz do stdout lub stderr w systemie Windows, a strumień jest TTY, libuv dokonuje własnej konwersji z UTF-8 na UTF-16. W ten sposób wyraźnie odmawia wyprowadzania zastępczych par, emitując zamiast tego zastępczy znak U+FFFD & # xFFFD; dla dowolnego punktu kodowania poza BMP.

Oto sprawcą 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; 
    } 

Komunikat throw pojawia się prawidłowo, ponieważ węzeł umożliwia Okna zrobić konwersję z UTF-8 do UTF-16 z MultiByteToWideChar() (która emituje zastępczych par) przed napisaniem wiadomości do konsoli. (Patrz PrintErrorString() in src/node.cc.)

+0

Brzmi nieźle. Brakujący szczegół w pytaniu polega na tym, że OP prawdopodobnie używa Win10. Wiele manipulacji wykonanych na konsoli w tej wersji, głównie w celu rozszerzenia obsługi nowego podukładu Linux. –

+0

A zatem zmodyfikowane 'libuv' (które akceptowałoby kod-punkty poza BMP i używało' MultiByteToWideChar') działałoby na Windows 10? - Brzmi jak ważna prośba o funkcję :) –

+0

@Hugues Moreau: Zakładam, że modyfikowanie _libuv_ na wyjściowe pary zastępcze UTF-16 pozwoli na wyświetlanie znaków innych niż BMP w strumieniach węzłów w konsoli Windows, która je obsługuje. Nie jest konieczne używanie 'MultiByteToWideChar()', w szczególności; usunięcie linii kodu pokazanej tutaj, a następnie dodanie "else" do następnego bloku do emisji zastępczej pary dla punktu kodowania powinno być wystarczające. Ale nie mam środowiska kompilacji dla konfiguracji Node.js (lub czasu lub skłonności do jej utworzenia!), Aby to wypróbować. –

2

(Zastrzeżenie: Nie mam rozwiązanie, ja zbadałem co czyni wyjątek obsługi specjalnych w odniesieniu do drukowania emotikonom, z narzędziami mam na systemie Windows 10 - Przy odrobinie szczęścia, które mogłyby poświęcić trochę światła na ten temat i być może ktoś coś rozpozna i zaproponuje rozwiązanie)

Wygląda jak kod raportowania wyjątków Node dla wywołań Windows do innego API Windows, który lepiej obsługuje Unicode.

Zobaczmy z Węzeł 7.10 źródeł:

ReportExceptionAppendExceptionLinePrintErrorString

W PrintErrorString, Windows specyficzny odcinek detects output type (tty/console or not): - Dla non-tty/kontekście konsoli zostanie wydrukowana do stderr (np. jeśli przekierujesz do pliku) - W konsoli cmd (bez przekierowania), będzie to convert tekst z MultiByteToWideChar(), a następnie pass do WriteConsoleW().

Gdybym uruchomić program za pomocą ConEmu (łatwiejsze niż uzyskanie standardowego cmd pracować z unicode & emotikonami - tak mam trochę leniwy tutaj), widzę coś podobnego jak to, co widziałeś: console.log nie zostanie wydrukowana emotikony, ale wiadomość emoji w wyjątku zostanie wydrukowana w porządku (nawet w glifie przewijania).

Jeśli przekieruje wszystkie dane wyjściowe do pliku (node test.js > out.txt 2>&1, tak, że działa również w systemie Windows cmd), otrzymam "czysty" Unicode w obu przypadkach.

Wygląda na to, że program drukuje do stdout lub stderr w konsoli systemu Windows, ale przed ponownym drukowaniem konsola wykonuje pewne (złe) czynności związane z ponownym kodowaniem. Gdy program używa interfejsu API konsoli systemu Windows bezpośrednio (wykonując samą konwersję z MultiByteToWideChar, a następnie napisz na konsolę z WriteConsoleW()), konsola pokazuje chwalebny niezmieniony emoji.

Gdy program JS używa funkcji console API do rejestrowania danych, być może Node może spróbować (w systemie Windows) wykryć konsolę i zrobić to samo, co w przypadku zgłaszania wyjątków. Zobacz @BrianNixon's answer, który wyjaśnia, co faktycznie dzieje się w libuv.