Unicode Box Drawing characters not printed in Ruby

2019-08-31 14:21发布

I work on a game in Ruby. It uses ncurses to draw window contents and refresh the screen. This all works fine on macOS, where I develop the stuff. But on Linux, I cannot get anything besides plain ASCII to print when interfacing with ncurses either from Ruby or plain C.

For example, I get this output:

Hello, world! M-b~U~TM-b~U~PM-b~U~WM-b~U~QM-b~U~QM-b~U~ZM-b~U~PM-b~U~]M-b~U~_M-b~T~@M-b~UM-"

Instead of what I put into the source:

Hello, world! ╔═╗║║╚═╝╟─╢

File encoding is UTF-8, env or locale output reports LANG and LC_* variables to be en_US or en_US.UTF-8 where appropriate. The terminal can print these characters just fine, so it's not the font or terminal emulator setting.

Python 3 works fine, too. Ruby and C don't.

(Tested on a fresh Linux Mint 19 setup with libncurses5-dev installed.)

So, Am I missing some setting or is the Python binding somewhat special and I'm out of luck?


What it looks like

It should look like this (macOS):

macOS reference pic

But does look like this instead:

ruby on linux

Python Code

This code works just fine:

#!/usr/bin/python
# -*- coding: utf-8 -*-

import locale
import curses

locale.setlocale(locale.LC_ALL, '')

stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.addstr(0, 0, "╔═╗║║╚═╝╟─╢") # dont even need .encode('UTF-8')
stdscr.refresh()
stdscr.getkey()
curses.endwin()

The docs for the curses module state that you have to do this since ncurses 5: https://docs.python.org/3/library/curses.html

Since version 5.4, the ncurses library decides how to interpret non-ASCII data using the nl_langinfo function. That means that you have to call locale.setlocale() in the application and encode Unicode strings using one of the system’s available encodings.

Ruby Code

# coding: utf-8
require "curses"

Curses.init_screen
Curses.start_color
Curses.stdscr.keypad(true) # enable arrow keys
Curses.cbreak # no line buffering / immediate key input
Curses.ESCDELAY = 0
Curses.curs_set(0) # Invisible cursor
Curses.noecho # Do not print keyboard input

Curses.stdscr.addstr(STYLES[:single])
Curses.stdscr.setpos(2,0)
Curses.stdscr.addstr(%Q{╔═╗║║╚═╝╟─╢})

Curses.getch

Tried with the ffi-ncurses gem instead of curses but to no avail. The output is the same.

C Code

I compile with

gcc -finput-charset=UTF-8 -fexec-charset=UTF-8 -pedantic -Wall -o main main.c -lncurses

Here's the code:

// Most of the code is sample code from "CURHELLO.C"
// (c) Copyright Paul Griffiths 1999

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <langinfo.h>
#include <locale.h>
#include <ncurses.h>

int main(void) {

    // Here I tried to copy what Python is doing:
    setlocale(LC_ALL, ""); // Also tried "C.UTF-8", "en_US.UTF-8"
    nl_langinfo(CODESET);


    WINDOW * mainwin;
    if ( (mainwin = initscr()) == NULL ) {
        fprintf(stderr, "Error initialising ncurses.\n");
        exit(EXIT_FAILURE);
    }

    start_color();
    clear();
    cbreak();
    noecho();
    keypad(stdscr, TRUE);

    mvaddstr(1, 1, "Hello, world! ╔═╗║║╚═╝╟─╢");
    refresh();
    sleep(3);

    delwin(mainwin);
    endwin();
    refresh();

    return EXIT_SUCCESS;
}

Edit

Got it working by linking to ncursesw (note the trailing W!), but it displays the special characters at double the width of text on Linux, using Ubuntu Mono, the same font I tried on OSX with iTerm.

enter image description here

1条回答
来,给爷笑一个
2楼-- · 2019-08-31 14:38

Actually this should be several questions, but the most recent one asks how the characters could be shown as double-width.

The screenshot does not match the given example program. That only draws a few sample characters, while the screenshot shows boxes.

However, the particular line-drawing characters can be the problem, versus the locale tables (and depending on the actual program used). That's because those codes are ambiguous width (see U+2550). The standard leaves it up to the implementer whether to treat them as single-width or double-width. Not everyone agrees on the actual width.

If this were a bug report, I'd get the actual program source to test with, but suspect the problem lies in Ruby.

查看更多
登录 后发表回答