銀月の符号

Python 使い見習いの日記・雑記

『065:文字列を最大nバイトに切り詰める』は codecs モジュールまかせでもできた

終わった…あっさりと。文字コードと戯れていたオレってなんだったんだろう。

# coding: utf-8

from codecs import getincrementaldecoder, iterencode

def _iter_mbchar(iterator, encoding, errors='strict', **kwargs):
    decoder = getincrementaldecoder(encoding)(errors, **kwargs)
    mbchar = []
    for input in iterator:
        mbchar.append(input)
        output = decoder.decode(input)
        if output:
            yield ''.join(mbchar)
            del mbchar[:]
    output = decoder.decode("", True)
    if output:
        yield ''.join(mbchar)

def take_nbytes_str(str_, n, encoding, errors='strict', **kwargs):
    u"""
    文字列 str_ を最大 n バイトに切り詰める

    str_:     8 ビット文字列
    n:        最大のバイト数。これより長い場合、切り詰める
    encoding: str_ の文字コード
    errors:   コーデックが用いるエラー処理方法
    **kwargs: コーデックに渡すオプション
    """
    length = 0
    temp = []
    for mbchar in _iter_mbchar(str_, encoding, errors, **kwargs):
        length += len(mbchar)
        if length > n:
            break
        temp.append(mbchar)
    return ''.join(temp)

def take_nbytes_unicode(unicode_, n, encoding, errors='strict', **kwargs):
    u"""
    ユニコード文字列 unicode_ をエンコードする、ただし最大 n バイトまで

    unicode_: ユニコード文字列
    n:        最大のバイト数。出力結果がこれより長くなることはない
    encoding: 文字コード
    errors:   コーデックが用いるエラー処理方法
    **kwargs: コーデックに渡すオプション
    """
    length = 0
    temp = []
    for mbchar in iterencode(unicode_, encoding, errors, **kwargs):
        length += len(mbchar)
        if length > n:
            break
        temp.append(mbchar)
    return ''.join(temp)

def _test():
    def _write(f, code):
        s = u'あいうえおかきくけこさしすせそたちつてと'.encode(code)
        for i in range(1, 40):
            f.write(''.join(take_nbytes_str(s, i, code)))
            f.write('\n')
        u = u'あいうえおかきくけこさしすせそたちつてと'
        for i in range(1, 40):
            f.write(''.join(take_nbytes_unicode(u, i, code)))
            f.write('\n')
    f_sjis = open('_sjis.txt', 'w')
    try:
        _write(f_sjis, 'shift_jis')
    finally:
        f_sjis.close()
    f_euc = open('_euc.txt', 'w')
    try:
        _write(f_euc, 'euc_jp')
    finally:
        f_euc.close()
    f_utf8 = open('_utf8.txt', 'w')
    try:
        _write(f_utf8, 'utf_8')
    finally:
        f_utf8.close()

if __name__ == '__main__':
    _test()