如何在Python的curses库中使用扩展字符?

4

我一直在阅读关于Python中Curses编程的教程,其中许多都提到了使用扩展字符的能力,例如绘制线条符号。它们是大于255的字符,而curses库知道如何在当前终端字体中显示它们。

有些教程说你可以像这样使用它:

c = ACS_ULCORNER

...有些人说你可以像这样使用它:

c = curses.ACS_ULCORNER

这应该是一个盒子的左上角,就像一个垂直翻转的L。

无论我使用哪种方法,名称都未定义,程序因此失败。我尝试过 "import curses" 和 "from curses import *",但都没有成功。

Curses 的 window() 函数使用了这些字符,所以我甚至尝试在我的盒子上寻找源代码,看看它是如何实现的,但我找不到它的任何地方。

3个回答

5
你需要将本地设置为all,然后按照以下方式将输出编码为utf-8:
import curses
import locale

locale.setlocale(locale.LC_ALL, '')    # set your locale

scr = curses.initscr()
scr.clear()
scr.addstr(0, 0, u'\u3042'.encode('utf-8'))
scr.refresh()
# here implement simple code to wait for user input to quit
scr.endwin()

输出:


4

来自curses/__init__.py:

一些常量,尤其是ACS_*这些常量,只有在调用initscr()之后才会添加到C _curses模块的字典中。(SGI的某些版本的curses直到调用了initscr()才定义了这些常量的值)。这个包装函数调用底层的C initscr(),然后将常量从_curses模块复制到curses包的字典中。如果您需要使用ACS_*常量,请不要执行'from curses import *'。

换句话说:

>>> import curses
>>> curses.ACS_ULCORNER
exception
>>> curses.initscr()
>>> curses.ACS_ULCORNER
>>> 4194412

1
感谢您的支持;要从Python的“curses”中转储可用的ACS定义,可以使用以下命令:python -c 'import pprint,inspect,curses ; curses.initscr() ; outstr= pprint.pformat(inspect.getmembers(curses)); curses.endwin() ; print(outstr)' | grep ACS。祝好! - sdaau

4
我相信以下内容是相关的,可以在此问题下发布。在这里我将使用utfinfo.pl(还可以在超级用户上查看)。
首先,对于标准ASCII字符集,Unicode代码点和字节编码是相同的:
$ echo 'a' | perl utfinfo.pl 
Char: 'a' u: 97 [0x0061] b: 97 [0x61] n: LATIN SMALL LETTER A [Basic Latin]

那么在Python的curses模块中,我们可以这样做:

window.addch('a')
window.border('a') 

...并且它按预期工作。

然而,如果一个字符位于基本ASCII之上,则会存在差异,addch 文档没有明确指出。首先,我可以这样做:

window.addch(curses.ACS_PI)
window.border(curses.ACS_PI)

如果你使用gnome-terminal,那么Unicode字符'π'将被渲染。然而,如果你检查ACS_PI,你会看到它是一个整数,值为4194427 (0x40007b);因此,下面的代码也会渲染相同的字符(或者说字形?)'π':

window.addch(0x40007b)
window.border(0x40007b)

为了了解发生了什么,我在ncurses源代码中进行了grep搜索,并找到了以下内容:
#define ACS_PI      NCURSES_ACS('{') /* Pi */  
#define NCURSES_ACS(c)  (acs_map[NCURSES_CAST(unsigned char,c)])
#define NCURSES_CAST(type,value) static_cast<type>(value)
#lib_acs.c: NCURSES_EXPORT_VAR(chtype *) _nc_acs_map(void): MyBuffer = typeCalloc(chtype, ACS_LEN);
#define typeCalloc(type,elts) (type *)calloc((elts),sizeof(type))
#./widechar/lib_wacs.c: { '{',  { '*',  0x03c0 }},  /* greek pi */

在这里注释:

$ echo '{π' | perl utfinfo.pl 
Got 2 uchars
Char: '{' u: 123 [0x007B] b: 123 [0x7B] n: LEFT CURLY BRACKET [Basic Latin]
Char: 'π' u: 960 [0x03C0] b: 207,128 [0xCF,0x80] n: GREEK SMALL LETTER PI [Greek and Coptic]

两者都与 ACS_PI 的值4194427 (0x40007b) 无关。

因此,当addch和/或border看到一个高于ASCII的字符(基本上是一个unsigned int,而不是unsigned char)时,它们(至少在这种情况下)使用该数字不是作为Unicode代码点或UTF-8编码字节表示 - 而是将其用作acs_map映射函数的查找索引(尽管最终会模拟VT-100返回Unicode代码点)。 这就是以下规范的原因:

window.addch('π') 
window.border('π') 

在Python 2.7中,将会出现argument 1 or 3 must be a ch or an int的错误;而在Python 3.2中,它将只呈现为空格而不是字符。当我们指定'π'时,实际上指定了UTF-8编码[0xCF,0x80],但即使我们指定Unicode代码点:

window.addch(0x03C0) 
window.border0x03C0) 

在Python 2.7和3.2中,如果直接使用addch函数输出字符串,会导致输出为空格。

但请注意,addstr函数可以正常接受UTF-8编码的字符串并输出:

window.addstr('π')

对于边框 - 因为border()显然与addch()以相同的方式处理字符 - 对于任何未明确指定为ACS常量的内容(而且这些常量并不多),我们似乎没有办法。

希望这能帮助到某些人,
干杯!


为什么当我使用std.addch(y, x, curses.ACS_PI)时,它会打印一个开放的花括号而不是PI符号? - KDM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接