DBD::SQLiteの入出力をちゃんと考えてみる

2010年1月 4日
| コメント(0) | トラックバック(0) DBD::SQLiteの入出力をちゃんと考えてみる

なんとか上手くいく方法はないものかと。

定石では、標準出力は『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は手軽に使えるので、使い方をちゃんと考えてみるのも良いもんだ。

トラックバック(0)

このブログ記事に対するトラックバックURL:

コメントする

Google検索

Last.fm

このブログ記事について

このページは、のぶりんが2010年1月 4日 23:19に書いたブログ記事です。

ひとつ前のブログ記事は「帰国」です。

次のブログ記事は「Strawberry Perlでminicpanを使えるようになるまで」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Creative Commons License
このブログのライセンスは クリエイティブ・コモンズライセンス.
Powered by Movable Type