なんとか上手くいく方法はないものかと。
定石では、標準出力は『binmode STDOUT, ':encoding(shiftjis)';』でutf8からshiftjisに変換できるはずですが、なぜか上手く行かず 。
普段から「binmode STDOUT => ":encoding(cp932)";」をよく使うので、なんとかならないかやってみました。
やってみればちゃんと出来るものです。
基本的には、Perlの内部形式の考え方をおさらいする形になった。
プログラムで扱う前にdecode、出力するときはencodeする。
それは、標準入出力だろうが、データベースだろうが、同じ扱い、ということ。
SQLiteはutf8の入出力が(少なくともver3.6.13では)可能のようだ。
まずは出力の時、データベースに渡すステートメントは「Encode::encode_utf8」してから出力する。
そして入力の時、つまり、データベースからデータを取る時は、とって来た後に「Encode::decode_utf8」する。
イメージは下の図。
今回は出力だけなのでSTDINは使っていないが、binmode STDOUTをencodingで使う場合は、あわせて指定しておくのが定石だと思われる。
| |→(binmode STDIN )→| |→(encode_utf8)→| | |DOS画面| |Perl内部| |データベース| | |←(binmode STDOUT)←| |←(decode_utf8)←| |
「binmode STDOUT => ":encoding(cp932)";」とやる場合、printする時は内部形式のまま出力するように書けばいいので、他には何もすることがない。
他にも挙動を調べたかったので、中身は少し変えた。
スクリプト
# utf8
use 5.8.1;
use strict;
use warnings;
use utf8;
use DBI;
use Encode;
my $lang_code = 'cp932';
binmode STDOUT => ":encoding($lang_code)";
my $database = ':memory:';# DBD::SQLite ver1.27以降
my @dsn = (
"dbi:SQLite:dbname=$database",
);
my $dbh = DBI->connect(@dsn);
printn("ver" . $dbh->{sqlite_version});
my $create_table = 'CREATE TABLE IF NOT EXISTS books (' .
'タイトル,' .
'著者' .
');';
sub_do($dbh, $create_table);
# insert文の実行
my $statement;
$statement = qq/insert into books (タイトル, 著者) values ('Perl', '啓仁');/;
sub_do($dbh, $statement);
$statement = qq/insert into books (タイトル, 著者) values ('C++', '成憲');/;
sub_do($dbh, $statement);
$statement = qq/insert into books (タイトル, 著者) values ('C#', '☺鳳☻');/;
sub_do($dbh, $statement);
$statement = q/insert into books (タイトル, 著者) values ('Python', '☻鳳☺');/;
sub_do($dbh, $statement);
$statement = q/insert into books (タイトル, 著者) values ('Java', 'Keva');/;
sub_do($dbh, $statement);
# update文の実行
$statement = q/update books set タイトル = 'Ruby' where 著者 = '成憲'/;# 著者が'成憲'のタイトルを「Ruby」に更新
sub_do($dbh, $statement);
# delete文の実行
$statement = q/delete from books where 著者 = '☻鳳☺';/;
sub_do($dbh, $statement);
# select文の実行
my $sth = $dbh->prepare("select * from books;");
$sth->execute;
# 各行のフェッチ
while (my $row = $sth->fetchrow_arrayref) {
# 各行を出力
my $str = $row->[0] . ":" . $row->[1];
$str = Encode::decode_utf8($str);
printn($str);
}
undef $sth;
# データベースの切断
$dbh->disconnect;
sub sub_do {
my ($dbh, $statement) = @_;
$statement = Encode::encode_utf8($statement);
$dbh->do($statement);
}
sub printn {
print @_;
print "\n";
}
実行結果
"\x{263a}" does not map to cp932.
"\x{263b}" does not map to cp932.
ver3.6.13
Perl:啓仁
Ruby:成憲
C#:\x{263a}鳳\x{263b}
Java:Keva
SQLiteは手軽に使えるので、使い方をちゃんと考えてみるのも良いもんだ。


コメントする