Edited at

UTF-8文字列として不正なバイト列を取り除くワンライナー

More than 1 year has passed since last update.

UTF-8文字列でマルチバイトの境界を意識せずにバイト数で文字列を切り捨てたりすると、

不正なバイト列が混じったりすることがあります。

たとえば こんにちわ という文字列を8バイトで切り捨ててみます。

$ ruby -e 'puts "こんにちわ".byteslice(0...8)'

こん

UTF-8で日本語のひらがなは 1文字で3バイトです。

こん の2文字までしか印字できていませんが、

odコマンドでバイト列を見てみると、末尾に不正なバイト列 e3 81 が混じっています。

$ ruby -e 'puts "こんにちわ".byteslice(0...8)' | od -tcx1

0000000 こ ** ** ん ** ** 343 201 \n
e3 81 93 e3 82 93 e3 81 0a
0000011

このように出力の文字列をパイプで後続のプログラムに渡したりすると、後続のプログラムが不正なバイト列を受け取ります。

根本的には、出力側が不正なバイト列にならないようにマルチバイトの境界を意識して、切り捨てるべきです。

例えば Ruby / Rails の場合

Ruby / Railsでマルチバイト文字の境界を意識しつつ指定のバイト数以下に切り捨てる

ただ出力側のプログラムが、簡単にいじれない場合は、さしあたりiconvコマンドで、不正なバイト列を除去することができます。

iconvの入出力のエンコードをutf-8で同じものを指定しつつ、 -c で変換できなかったバイトを捨てます。

$ ruby -e 'puts "こんにちわ".byteslice(0...8)' | iconv -f utf-8 -t utf-8 -c | od -tcx1

0000000 こ ** ** ん ** ** \n
e3 81 93 e3 82 93 0a
0000007

暫定の回避策としてお使い下さい。