2012-02-11
■[Ruby] マルチバイト文字を含む文字列の表示桁数を合わせる
マルチバイト文字を含む文字列の表示桁数を合わせる方法についてです。
printf や sprintf を使用して文字列の桁数を合わせようとすると、マルチバイト文字が含まれている場合に意図したとおりに表示桁数を合わせることができません。
例えば、以下のようにマルチバイト文字を含む文字列を 7 桁に揃えるコードを書いたとしても、表示桁数は不揃いになってしまいます。
puts '[' + sprintf('%7s', 'a') + ']' puts '[' + sprintf('%7s', 'aB') + ']' puts '[' + sprintf('%7s', 'aBc') + ']' puts '[' + sprintf('%7s', 'aBcD') + ']' puts '[' + sprintf('%7s', 'aBcDe') + ']' puts '[' + sprintf('%7s', 'aBcDeF') + ']'
出力結果:
[ a] [ aB] [ aBc] [ aBcD] [ aBcDe] [ aBcDeF]
Ruby 1.8 では文字列のバイト数、Ruby 1.9 では文字列の文字数を基準に桁数が調整されます。つまり、コンソール等に表示されるときの表示幅は考慮されません。表示幅はフォントによって異なるので、sprintf の動作は正しいです。
とはいえ、コンソール等に出力するときに表示桁数を合わせたい場合もあります。そこで、以下のような表示幅を求めるメソッドを定義し、独自にパディングを行うことで対応します。
# 文字列の表示幅を求める. def print_size(string) string.each_char.map{|c| c.bytesize == 1 ? 1 : 2}.reduce(0, &:+) end # 指定された表示幅に合うようにパディングする. def pad_to_print_size(string, size) # パディングサイズを求める. padding_size = size - print_size(string) # string の表示幅が size より大きい場合はパディングサイズは 0 とする. padding_size = 0 if size < 0 # パディングする. ' ' * padding_size + string end
上記のメソッドを実際に使用します(違いが分かりやすいように sprintf の結果も表示します)。
# Ruby 1.8 の場合は $KCODE を設定する. if RUBY_VERSION < '1.9' $KCODE = 'UTF-8' end puts '---- sprintf ----' puts '[' + sprintf('%7s', 'a') + ']' puts '[' + sprintf('%7s', 'aB') + ']' puts '[' + sprintf('%7s', 'aBc') + ']' puts '[' + sprintf('%7s', 'aBcD') + ']' puts '[' + sprintf('%7s', 'aBcDe') + ']' puts '[' + sprintf('%7s', 'aBcDeF') + ']' puts '---- pad_to_print_size ----' puts '[' + pad_to_print_size('a', 7) + ']' puts '[' + pad_to_print_size('aB', 7) + ']' puts '[' + pad_to_print_size('aBc', 7) + ']' puts '[' + pad_to_print_size('aBcD', 7) + ']' puts '[' + pad_to_print_size('aBcDe', 7) + ']' puts '[' + pad_to_print_size('aBcDeF', 7) + ']'
出力は以下の通りです。
---- sprintf ---- [ a] [ aB] [ aBc] [aBcD] [aBcDe] [aBcDeF] ---- pad_to_print_size ---- [ a] [ aB] [ aBc] [ aBcD] [aBcDe] [aBcDeF]
トラックバック - http://d.hatena.ne.jp/benikujyaku/20120211/1328934654