プロが教える店舗&オフィスのセキュリティ対策術

2バイト文字、1バイト文字どちらもありうる(構成が不明である)文字列をバイト単位で桁揃えして出力したいのですが、
use encoding 'cp932';
printf "|%2s\n|","あ";
printf "|%2s\n|","aa";
とすると、出力結果は当然
| あ|
|aa|
となって、桁が揃わないですよね。「バイト単位で2バイト分の巾」という指定を実現するにはどうしたらいいのでしょうか。日本語処理ではよくある問題だと思うのですが。

A 回答 (2件)

ちょっと裏技的に


use Encode ;

binmode(STDOUT,":bytes") ; # バイトコードをそのまま出力させるように変更
printf "|%2s\n|",Encode::encode('cp932',"あ"); # cp932にencodeすれば、2バイト文字は「2バイト=2文字」扱いになる

既出の方法の方が汎用性はありますけど。
    • good
    • 0
この回答へのお礼

とりあえずはこの方法が簡単そうですので採用させていただこうかと思います。
どうもありがとうございました。

お礼日時:2011/10/02 10:37

# 表示がくずれるので空白2文字を全角空白にしていることに注意



use strict;
use warnings;
use utf8;
use Encode;
use Encode::CJKConstants;

my @hello_list = (
  'こんにちは、世界!!',     'Hello World!!',
  'HELLO WORLD!!', 'こんにちは、World。',
  "コンニチハ 世界.", '世界,你好!'
);

binmode STDOUT, ":encoding(utf8)";
for my $hello (@hello_list) {
  my $view_length = count_view_length($hello);
  my $char_length = length $hello;
  my $format   = '%-' . ( 32 - ( $view_length - $char_length ) ) . 's :';
  printf $format, $hello;
  print "\n";
}

# result。等幅フォントで見れば : (コロン)が揃っている
# こんにちは、世界!!       :
# Hello World!!          :
# HELLO WORLD!!    :
# こんにちは、World。       :
# コンニチハ 世界.           :
# 世界,你好!           :

sub count_view_length {
  my $str     = shift;
  my $view_length = 0;
  for my $char ( split q{}, $str ) {
    my $sjis_char = encode( 'sjis', $char );
    if ( $char =~ m/\p{InBasicLatin}/ ) {
      $view_length += 1;
    }
    elsif ( $sjis_char =~ m/^$Encode::CJKConstants::RE{SJIS_KANA}$/ ) {
      $view_length += 1;
    }
    else {
      $view_length += 2;
    }
  }
  return $view_length;
}
    • good
    • 0
この回答へのお礼

大変参考になりました。どうもありがとうございました。

お礼日時:2011/10/11 20:56

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!