0

UTF-8 でエンコードされた文字列を curses ウィンドウに出力しようとすると、非常に奇妙な問題に遭遇しました。これがコードです。正確な問題と、以下で試したことについて説明します。

# coding=UTF-8
import curses
import locale
import time
locale.setlocale(locale.LC_ALL, '')
code = locale.getpreferredencoding()



class AddCharCommand(object):
    def __init__(self, window, line_start, y, x, character):
        """
        Command class for adding the specified character, to the specified
        window, at the specified coordinates.
        """
        self.window = window
        self.line_start = line_start
        self.x = x
        self.y = y
        self.character = character


    def write(self):
        if self.character > 127:
            # curses somehow returns a keycode that is 64 lower than what it
            # should be, this takes care of the problem.
            self.character += 64
            self.string = unichr(self.character).encode(code)
            self.window.addstr(self.y, self.x, self.string)
        else:
             self.window.addch(self.y, self.x, self.character)


    def delete(self):
        """
        Erase characters usually print two characters to the curses window.
        As such both the character at these coordinates and the one next to it
        (that is the one self.x + 1) must be replaced with the a blank space.
        Move to cursor the original coordinates when done.
        """
        for i in xrange(2):
            self.window.addch(self.y, self.x + i, ord(' '))
        self.window.move(self.y, self.x)

def main(screen):
    maxy, maxx = screen.getmaxyx()
    q = 0
    commands = list()
    x = 0
    erase = ord(curses.erasechar())
    while q != 27:
        q = screen.getch()
        if q == erase:
            command = commands.pop(-1).delete()
            x -= 1
            continue
        command = AddCharCommand(screen, 0, maxy/2, x, q)
        commands.append(command)
        command.write()
        x += 1

curses.wrapper(main)

ここにGistへのリンクがあります。

問題は、èキー (ASCII コード 232 を持つ) を押しても、その文字だけが出力されないことです。代わりに、文字列ăèは指定された座標に出力されます。使用してみself.window.addstr(self.x, self.y, self.string[1])ましたが、意味不明な印刷が行われました。

次に、Python プロンプトを起動して戻り値を確認しましたunichr(232).encode('utf-8')が、実際には長さ 2 の文字列です。

非常に予期しない動作は、それを入れると、screen.addstr(4, 4, unichr(232).encode(code))文字mainが正しく表示され、èその文字のみが表示されることです。なんとしてでも文字を出力するクラスのwriteメソッドを作った場合も同様です。AddCharCommandè

もちろん、問題はèこれだけに限定されているわけではなく、ほとんどすべての拡張 ASCII 文字に当てはまります。

curses を使用した拡張 ASCII が少し不安定であることは知っていますが、この動作をまったく理解できません。ASCII コードをハードコーディングしても、コードが期待どおりに機能することは (私には) 意味がありませんが、そうしないと別の文字が追加されます。

私は周りを見回して、呪いに関するかなり多くのことを読みましたが、これに対する解決策を見つけることができませんでした. この問題について何か助けていただければ幸いです。それは私を怒らせています。

screen.getch()あまり重要ではないかもしれませんが、127 を超える文字に対して誤った ASCII コードを返す理由と、実際の ASCII コードと curses によって返されるコードの違いが 64 である理由を誰かが説明してくれれば幸いです。

事前にどうもありがとうございました。

4

1 に答える 1