Perlクライアントで日本語のデータを扱う際の注意

DoqueDBにはPerlのAPIも付属しています。

現時点ではこれといったマニュアルもなく、また、特別なインストーラーなどは準備しておりません。ソースコードの doqueDB/sydney/Perl フォルダー以下のファイル(DBDとNet以外にあるものは不要)を適当な場所に配置しておけば、perl のインクルードパス配列(@INC)に加えるだけで使用可能となります。
DBIの実装クラスとして実現されており、主要なメソッドは提供されているので、多くの操作は他のデータベースを扱う場合と同様に使用できます。doquedb/sydney/Perl/DBD/sqli.pl が、コマンドライン版のsqliのと同様のものを実装しているサンプルコードとなりますので、それを参照するとよいでしょう。

データベースへ接続する典型的なプログラムは、以下のようなコードから始まるはずです。

use lib qw(/path/to/DoqueDB/sydney/Perl/); #ライブラリの場所を指定
use DBI;
my $dbh = DBI->connect(join(q(;),
                q(dbi:TRMeisterPP:database=DefaultDB),  # データベース名
                q(host=hostname),                       # ホスト名
                q(port=54321)),                         # ポート番号
            q(root), q(doqadmin),                       # ユーザ名, パスワード
            {RaiseError => 0, printError => 0,          # エラー発生時の扱い
             userEncode => q(utf-8)}                    # データベースの文字コード
           );

後は、他のデータベースと同じように、取得したデータベースハンドル($dbh)に対して、prepare()メソッドでSQLを設定し、execute()で実行すればよいだけですので、ここではDBIのメソッドに関しては説明しません。

この記事では、日本語を扱う際の注意事項に関して述べます。
perlは、以前はデータはバイナリも文字列も区別なく扱っていましたが、Unicodeを扱うにあたって、順次改訂されています。バージョンによって動作が異なる点もあるので注意が必要なのですが、典型的なのは、文字列を扱う関数、特に正規表現などでもUnicodeが使えるようになったため、日本語処理をする際には、以前のように文字コードの内部のバイトのパターンで正規表現を書く必要はなくなりました。ただし、この際に UTF8フラグという概念が導入されております。これにより少し面倒な問題が起こります。

日本語などのutf-8でエンコードされた文字列を扱う際は、文字列処理を便利に行うためには、対象文字列のutf-8フラグがonになっている必要がありますが、prepare()などのメソッドに渡す場合、UTF8フラグをoffにしておく必要があります。

従って、perlのプログラムを記載する際は、ソースに直に記載された文字列、外部から受け取った文字列などは、UTF8フラグがどうなっているかを理解していないと、意味不明な警告やエラーに悩まされることになります。

perlのソースコードをutf-8で保存したとして、直に文字列を記載した場合は、その文字列のUTF8フラグはoffです。(ただし、use utf8;プラグマを使用した場合はonになります。)
また、外部からファイルを単純に、例えばwhile(<>){ $line = $_; }のような典型的なコードで、1行ずつ読み込んで文字列に格納した場合も、標準入力に対して特別な処理をしていない場合は、行を受け取った変数のUTF8フラグはoffです。

utf-8フラグを変更するには、以下のようなメソッドを使います。

use Encode;
my $decoded = Encode::decode('utf8', $str);     # UTF8フラグon
my $encoded = Encode::encode('utf8', $decoded); # UTF8フラグoff

Encodeモジュールは、文字コード変換にも用いることが多いモジュールなので、これらはむしろUTF8フラグの存在をユーザーに意識させないようなメソッド名になっており、これを使うのが安全とされていますが、詳細は複雑で、実際のところUTF8フラグを直接変更するメソッドもあります。

use Encode;
Encode::_utf8_on($str);
Encode::_utf8_off($str);

事前チェックなどを行わず、フラグを変更するだけなので、こちらの方が高速なのですが、マニュアルには内部メソッド扱いで、将来変更される可能性があるメソッドとなっております。また、フラグの値のチェックが必要な場合は、Encode::is_utf8()を使うことはできますが、今回はこの詳細には触れません。

また、Encodeモジュールを用いなくても、utf8::decode(), utf8::encode()を使用してUTF8フラグを変更することも可能です。

utf8::decode($str);   # UTF8フラグon
utf8::encode($str);   # UTF8フラグoff

これらは、Encodeモジュールのものとは異なり、直接引数の文字列を変更します。値チェックのためのutf8::is_utf8()も同様に提供されています。
perlのバージョンによってモジュールのバージョンも異なり、詳細な動作が異なる場合もありますので、お使いのperlのバージョンの該当するマニュアルを参照してください。記事末尾に最新版に対するリンクを入れておきます。

従って、utf-8でエンコードされたテキストファイルから行を読み込んで、DoqueDBで操作するようなコードは、以下のように記載することになります。ここでの説明では、入力ファイルのデータはutf-8のテキストで間違いがないものという前提で、_utf8_on(), _utf8_off()を使った記述としています。エラー処理は入っておりません。

use lib qw(/path/to/Perl/);
use DBI;
use Encode;
my $dbh = DBI->connect(...);
while(<>) {
  chomp(my $line = $_);
  # 文字列操作をしたいので、外部から得たデータのUTF8フラグをonにする。
  Encode::_utf8_on($line);
  # $line に対して文字列操作して、欲しい結果を $str に得る。
  my $str = do_something($line);
  # 外部に渡す前にUTF8フラグをoffにする。
 Encode::_utf8_off($str);
  # SQLを実行
  my $sth = $dbh->prepare(qq(
    select column from table where text contains ('$str');
  ));
  $sth->execute();
 # 結果取得
  while (my $row = $sth->fetch()) {
    my $column = $row->[0];
    # 取得したデータを操作したいので、UTF8フラグをonにする。
  Encode::_utf8_on($column);
    # $columnに対して文字列操作した結果を$resultに
  my $result = do_something($column);
    # 標準出力に渡す前もUTF8フラグはoffにする。
  Encode::_utf8_off($result);
    print STDOUT $result;
  }
}
$dbh->disconnect();

perlのUTF8フラグは、外部からデータを受け取ったらUTF8フラグをonに、外部に渡す前にoffにするというのが原則です。
なお、標準入出力などに関しては、受け取った時点でUTF8フラグをonにする方法もあります。

binmode STDOUT, ":utf8";

のように指定するか、openを使う場合は

open(FH, "<:utf8", $filename);

のように記載できます。
詳しくは、perlのマニュアル中、Encodeモジュールutf8プラグマや、perlunicodeを参照してください。perlunifaqも参考になります。

TOP