星期五, 4月 30, 2010

perl threads encoding

上一篇 講到了讓 DBI::SQLite 自動為 string 加上 utf-8 flag,其實是因為我最近在寫 gtk 的時候需要用到額外的 thread,但是 encoding (perl 內建的 package) 不是 thread-safe 而且只要一用,threading 就一定以 segmentation fault 收場。
我目前是沒有找到什麼解法,但是如果是使用不同編碼來寫 perl 那可能只能暫時用 package Encode 的 decode 或 encode 來把每個字串包起來吧 Orz. 天阿,好險我都用 utf-8

perl & utf-8 (SQLite issue)

事實上自從 perl 5.8.0 以後好像已經全面使用 unicode 了,根據我的了解 perl-gtk2 內部也都使用 utf-8,但是說也奇怪我的 gtk label 就是顯示不了中文,使用者輸入的中文卻又沒問題,找了許久才發現,perl 在 string 上會有一個 utf-8 flag,用來判斷這個 string 是不是使用 utf-8,不是的話 gtk2 的 module 會再做一次轉換,由於 db 讀出來的 string 都沒有設定,中文就爛掉了。

但是為什麼我 db 裡面明明存 utf-8 讀出來卻不是呢? DBI::SQLite 說道..
If the attribute $dbh->{sqlite_unicode} is set, strings coming from the database and passed to the collation function will be properly tagged with the utf8 flag; but this only works if the sqlite_unicode attribute is set before the first call to a perl collation sequence . The recommended way to activate unicode is to set the parameter at connection time :
所以只要確定 db 裡面是存著 utf-8 的資料,只要再連線時設定好 sqlite_unicode,sqlite 的 DBI 會幫你把 utf-8 flag turn on:
my $dbh = DBI->connect(
      "dbi:SQLite:dbname=foo", "", "",
      {
          RaiseError     => 1,
          sqlite_unicode => 1,
      }
  );
當然,總是有一些比較不一樣的方法,用 Encode::_utf8_on 可以直接把 flag turn on,可以在有用到中文的地方設定,但這樣不但瑣碎可能忘記,而且 gtk module 還會嘗試將其他不是 utf-8 的 string 再轉換一次,所以還是建議讓 DBI 把全部的 string set utf-8 flag。