エンコーディング検出ライブラリ「encdet」をリリース
さて、久しぶりなわけですが。
タイトルの通りリリースしました。
http://wiki.github.com/spiritloose/encdet
http://github.com/spiritloose/encdet/tree/master
Mozillaの「Mozilla Universal Charset Detector」というやつのCバインディングです。
MozillaのMercurialリポジトリからコピってきて、Cのインターフェースをつけてautotools化してみました。
http://www.void.in/wiki/Universalchardet っていうのもあったんですが、本家の方が結構変わってたり、
autotools化したかったり、もろもろあったので作りました。
#include <encdet.h> #include <string.h> #include <stdio.h> int main(int argc, char **argv) { char buf[BUFSIZ]; const char *encoding; encdet_t det = encdet_new(ENCDET_ALL); while ((fgets(buf, sizeof(buf), stdin)) != NULL) { encdet_handle_data(det, buf, strlen(buf)); } encdet_data_end(det); encoding = encdet_get_result(det); if (encoding) { puts(encoding); } else { puts("UNKNOWN"); } encdet_destroy(det); return 0; }
みたいな感じです。
メンテは、本家に追従していく予定です。
DELL SC-440をいろいろパワーアップ
この前新サーバ用に購入したDELL SC-440をいろいろパワーアップした。
メモリ
512MB→ Transcend TS128MLQ72V6J ×4
余った512はSC-430へ。
ハードディスク
80GB→80GB+Hitachi/IBM HDP725050GLA360(500GB)
SATAケーブル
SANWA SUPPLY TK-SATA-05BLL
本体とか送料とか全部込みで計¥44,408
コストパフォーマンス抜群すぎる。
OSはUbuntu Hardy Heronを入れた。
用途は、ジュークボックス兼ファイルサーバ兼開発サーバ(VMwareで)。
会社ではXenをずっとつかってるんだけど、今回はいろんなOSを完全仮想化でサクッと使いたかったのでVMwareを選択。
今のところゲストOSを7つ動かしている。
まっさらな環境がすぐにできるので、動作確認用にも便利。
これで分散環境のテストも容易になった。
開発がはかどる・・・といいな。
MySQLのトリガでシーケンスでの自動採番を実現する
同じデータベースの違うテーブルでプライマリキーを重複させたくない場合や、
クラスタ化した場合とかで AUTO_INCREMENT が使えない場合。
いわゆる採番テーブルってやつ。
DBICとかで
sub nextval { my $self = shift; my $dbh = $self->result_source->storage->dbh; my $sql = 'UPDATE sequence SET id = LAST_INSERT_ID(id + 1)'; my $sth = $dbh->prepare($sql); $sth->execute; my $id = $sth->{mysql_insertid}; $sth->finish; $id; }
とか手動でやってもよかったんだけど、せっかくなのでMySQLのトリガーでやってみた。
DROP TABLE IF EXISTS sequence; CREATE TABLE sequence (id INT UNSIGNED NOT NULL); INSERT INTO sequence VALUES (100000); DROP TABLE IF EXISTS hoge; CREATE TABLE hoge ( id INT UNSIGNED NOT NULL PRIMARY KEY, content TEXT ); DROP TRIGGER IF EXISTS hoge_set_id; delimiter // CREATE TRIGGER hoge_set_id BEFORE INSERT ON hoge FOR EACH ROW BEGIN UPDATE sequence SET id = LAST_INSERT_ID(id + 1); SET NEW.id = LAST_INSERT_ID(); END; // delimiter ;
とこんな感じで作って、
(root@localhost) [test]> INSERT INTO hoge (content) VALUES ('hoge'); Query OK, 1 row affected, 1 warning (0.01 sec) (root@localhost) [test]> SELECT * FROM hoge; +--------+---------+ | id | content | +--------+---------+ | 100001 | hoge | +--------+---------+ 1 rows in set (0.01 sec) (root@localhost) [test]>
いけた。が、なんか warning でてる。
(root@localhost) [test]> SHOW WARNINGS; +---------+------+-----------------------------------------+ | Level | Code | Message | +---------+------+-----------------------------------------+ | Warning | 1364 | Field 'id' doesn't have a default value | +---------+------+-----------------------------------------+ 1 row in set (0.00 sec)
まぁそうだけどさ・・・BEFOREトリガ呼んだあとに確認してくれないものか。
ダミーデータを入れたら当然出なくなるが、あまり気持ちのいいものではない。
(root@localhost) [test]> INSERT INTO hoge (id, content) VALUES (0, 'hoge'); Query OK, 1 row affected (0.01 sec)
sql/sql_insert.cc を軽く追ったところ、やはりBEFORE INSERT のトリガ呼ぶ前にエラーメッセージをセットしてるっぽい。
まぁ気にしないことにした。
意外とこの方法は使えるかも。割とお手軽だし、アプリケーションに依存しない。
サーバが複数にまたがってる場合は FEDERATED を使えばいけるんじゃないか(試してないけど)。
関係ないが、Data::YUIDはそろそろ使ってみたい。
UTF-8 の範囲外の文字かどうか調べる
UTF-8 の範囲外の文字かどうか、どうやって判別したらいいのだろう - @kyanny's blog
こんなんでどうでしょうか。
check_utf8.pl
#!/usr/local/bin/perl use strict; use warnings; use Encode; while (<>) { eval { decode_utf8($_, Encode::FB_CROAK); }; if ($@) { warn "line $.: invalid utf-8 string"; } }
というか、decode_utf8できるかってことだけど。
適当に
$ cat utf8.txt euc-jp.txt sjis.txt utf8.txt > mixed.txt $ ./check_utf8.pl < mixed.txt
とかで。
追記
なんとなくUTF-8じゃない部分のエンコーディングと復元したデータを表示するようにした。
#!/usr/local/bin/perl use strict; use warnings; use utf8; use Encode; use Encode::Detect::Detector; binmode STDOUT => ':encoding(euc-jp)'; while (my $octets = <>) { eval { decode_utf8($octets, Encode::FB_CROAK); }; next unless $@; print "line $.: invalid utf-8 string found\n"; my $encoding = detect($octets) || 'Windows-1252'; my $e = find_encoding($encoding); if ($e) { print "encoding: $encoding\n"; printf 'data: %s'. "\n", $e->decode($octets); } else { print "Unknown encoding: $encoding\n"; } }
$ ./check_utf8.pl < mixed.txt line 2: invalid utf-8 string found encoding: EUC-JP data: こんにちわ line 3: invalid utf-8 string found encoding: Shift_JIS data: こんにちわ
よしよし。
Ruby 1.9.0-1で Encoding.list がすごい増えた
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/33947
$ /usr/local/ruby-1.9.0-1/bin/ruby -e 'puts Encoding.list'
ASCII-8BIT UTF-8 US-ASCII Big5 CP949 EUC-JP EUC-KR EUC-TW GB18030 GBK ISO-8859-1 ISO-8859-2 ISO-8859-3 ISO-8859-4 ISO-8859-5 ISO-8859-6 ISO-8859-7 ISO-8859-8 ISO-8859-9 ISO-8859-10 ISO-8859-11 ISO-8859-13 ISO-8859-14 ISO-8859-15 ISO-8859-16 KOI8-R KOI8-U Shift_JIS UTF-16BE UTF-16LE UTF-32BE UTF-32LE Windows-1251 IBM437 IBM737 IBM775 CP850 IBM852 CP852 IBM855 CP855 IBM857 IBM860 IBM861 IBM862 IBM863 IBM864 IBM865 IBM866 IBM869 Windows-1258 GB1988 macCentEuro macCroatian macCyrillic macGreek macIceland macRoman macRomania macThai macTurkish macUkraine eucJP-ms CP51932 GB2312 GB12345 ISO-2022-JP ISO-2022-JP-2 Windows-1252 Windows-1250 Windows-1256 Windows-1253 Windows-1255 Windows-1254 TIS-620 Windows-874 Windows-1257 Windows-31J MacJapanese UTF-7
すばらしい!
こんなにCSIで扱えるなんて。
Ruby 1.9のm17nで幸せになれる人いっぱいいるんじゃなかろうか。
Perlと比べてみる。
$ piconv -l | wc -l 123 $ /usr/local/ruby-1.9.0-1/bin/ruby -e 'puts Encoding.list' | wc -l 80
PerlはEncode::HanExtraとかその他もろもろ入れるともっと増えるが・・・
PerlはUCSだけど。
とりあえずPHPのmbstringよりはすでに多い。
最近買った本
友人のid:clonedさんが記事を書いたと聞いて。
そのid:clonedさんにオススメされて。
Sennaが載ってると聞いて。
なんで買ったのか忘れた。
大きかった。持ち歩く気がしないので家で読む用。
以下雑多な感じ。
あとDVDを一枚を加えて計8点一括発送で注文したんだが、思考する機械コンピュータ1冊だけ先に届いた。
残りの7点は例によって明らかに内容量より大きな箱で届いた。
ダンボールまじ勘弁して。
そんで、2日連続同じドライバーの方に再配達の電話したら2回目は名前だけで持ってきてくれた。