謎's キッチン

謎のひとりごと。Amazon欲しい物リストはこちら: https://www.amazon.co.jp/hz/wishlist/ls/CCPOV7C6JTD2

Pythonで日本語出力

2chを参考にしながら作ってみたが、バイナリ表示に一苦労。
コマンド プロンプトはエスケープシーケンスをサポートしてなかったという罠。ビープ音は出るのに…。
utf-16のBOMを区切りとして使って無理やり実装。
Python良く知らんのや面倒という理由でコードは汚い。
コード整理して更新。

if sys.platform == 'win32':
    from ctypes import windll, Structure, c_short, c_ushort, byref
    import codecs

    class COORD(Structure):
        _fields_ = [
            ("X", c_short),
            ("Y", c_short)
        ]

    class SMALL_RECT(Structure):
        _fields_ = [
            ("Left", c_short),
            ("Top", c_short),
            ("Right", c_short),
            ("Bottom", c_short)
        ]

    class CONSOLE_SCREEN_BUFFER_INFO(Structure):
        _fields_ = [
            ("dwSize", COORD),
            ("dwCursorPosition", COORD),
            ("wAttributes", c_ushort),
            ("srWindow", SMALL_RECT),
            ("dwMaximumWindowSize", COORD)
        ]

    STD_OUTPUT_HANDLE = -11
    STD_ERROR_HANDLE = -12

    def consolereplace_errors(exception):
        if not isinstance(exception, UnicodeDecodeError):
            raise TypeError("consolereplace() cannot handle %r" % exception)
        l = [u"\\%x" % ord(exception.object[pos]) for pos in xrange(exception.start, exception.end)]
        return (u"\ufffe%s\ufeff" % u"".join(l), exception.end)

    codecs.register_error("consolereplace", consolereplace_errors)

    FOREGROUND_RED = 4

    class WindowsConsoleWriter:
        def __init__(self, stdhandle, errors='strict'):
            self.errors = errors
            self.encoding = 'utf_16'
            self.handle = windll.kernel32.GetStdHandle(stdhandle)

            csbi = CONSOLE_SCREEN_BUFFER_INFO()
            windll.kernel32.GetConsoleScreenBufferInfo(self.handle, byref(csbi))

            self.defattr = csbi.wAttributes

        def writelines(self, text):
            self.write(text + "\n")

        def _write(self, text):
            windll.kernel32.WriteConsoleW(self.handle, text, len(text), 0, 0)

        def _color(self, color):
            windll.kernel32.SetConsoleTextAttribute(self.handle, color)

        def write(self, text):
            text = unicode(text, 'utf_8', errors='consolereplace')
            i = 0
            j = 0
            for c in text:
                if c == u'\ufffe':
                    self._write(text[i:j])
                    i = j+1
                    self._color(FOREGROUND_RED)
                elif c == u'\ufeff':
                    self._write(text[i:j])
                    i = j+1
                    self._color(self.defattr)
                j+=1
            self._write(text[i:j])

        def isatty(self): return True 

        def flush(self): pass

    if sys.stdout.isatty():
        sys.stdout = WindowsConsoleWriter(STD_OUTPUT_HANDLE)
    if sys.stderr.isatty():
        sys.stderr = WindowsConsoleWriter(STD_ERROR_HANDLE)


64bitが駄目かも。
あとライセンスは自由に再ライセンスができるWTFPL-2で。