はじめに
データ連携などでエクスポート機能などを実装するとき、特定のバイト数まで切り詰める処理が必要になる事があります。データがASCII文字だけで構成されていれば簡単なのですが、日本語などのマルチバイト文字が含まれていると文字数とバイト数に差が生じます。マルチバイト文字を分断することなく指定されたバイト数に切り出す処理を Python3 で実装してみました。
ソースコード
truncate.py
'''
>>> str = 'abcdeあいうえお'
>>> truncate(str, 7) # 5bytes in utf-8
'abcde'
>>> truncate(str, 8) # 8bytes in utf-8
'abcdeあ'
>>> truncate(str, 9) # 8bytes in utf-8
'abcdeあ'
>>> truncate(str, 12) # 11bytes in utf-8
'abcdeあい'
>>> truncate(str, 12, encoding='cp932') # 11bytes in cp932
'abcdeあいう'
>>> truncate(str, 12, encoding='euc-jp') # 11bytes in euc-jp
'abcdeあいう'
'''
def truncate(str, num_bytes, encoding='utf-8'):
while len(str.encode(encoding)) > num_bytes:
str = str[:-1]
return str
やっていることは単純で、今のバイト数が指定されたバイト数を超えている間、繰り返し後ろ1文字を削除しています。今回、どの文字コードでバイト数をカウントするかも選べるようにしました。
doctest にも対応しています。下記のように実行して、動作を確認してみてください。
実行
(venv35)$ python -m doctest -v truncate.py
Trying:
str = 'abcdeあいうえお'
Expecting nothing
ok
Trying:
truncate(str, 7) # 5bytes in utf-8
Expecting:
'abcde'
ok
Trying:
truncate(str, 8) # 8bytes in utf-8
Expecting:
'abcdeあ'
ok
Trying:
truncate(str, 9) # 8bytes in utf-8
Expecting:
'abcdeあ'
ok
Trying:
truncate(str, 12) # 11bytes in utf-8
Expecting:
'abcdeあい'
ok
Trying:
truncate(str, 12, encoding='cp932') # 11bytes in cp932
Expecting:
'abcdeあいう'
ok
Trying:
truncate(str, 12, encoding='euc-jp') # 11bytes in euc-jp
Expecting:
'abcdeあいう'
ok
1 items had no tests:
main.truncate
1 items passed all tests:
7 tests in main
7 tests in 2 items.
7 passed and 0 failed.
Test passed.