エンコーディング検出ライブラリ「encdet」をリリース


さて、久しぶりなわけですが。


タイトルの通りリリースしました。

http://wiki.github.com/spiritloose/encdet
http://github.com/spiritloose/encdet/tree/master


Mozillaの「Mozilla Universal Charset Detector」というやつのCバインディングです。

MozillaMercurialリポジトリからコピってきて、Cのインターフェースをつけてautotools化してみました。


http://www.void.in/wiki/Universalchardet っていうのもあったんですが、本家の方が結構変わってたり、
autotools化したかったり、もろもろあったので作りました。

今のところ LinuxFreeBSDで動作確認してます。

#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


サウンドカード
なし→AOpen Cobra AW850


本体とか送料とか全部込みで計¥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さんが記事を書いたと聞いて。


すべてがFになる―THE PERFECT INSIDER (講談社文庫)
森 博嗣
講談社 (1998/12)
売り上げランキング: 2655

そのid:clonedさんにオススメされて。


ウェブ国産力―日の丸ITが世界を制す (アスキー新書 047)
佐々木 俊尚
アスキー (2008/01/10)
売り上げランキング: 1576

Sennaが載ってると聞いて。


思考する機械コンピュータ (サイエンス・マスターズ)
ダニエル ヒリス W.Daniel Hillis 倉骨 彰
草思社 (2000/10)
売り上げランキング: 4586

なんで買ったのか忘れた。


ハッカーズ
ハッカーズ
posted with amazlet on 08.02.28
ティーブン・レビー 松田 信子 古橋 芳恵
工学社 (1987/02)
売り上げランキング: 136474

大きかった。持ち歩く気がしないので家で読む用。


以下雑多な感じ。

李登輝学校の教え (小学館文庫)
李 登輝 小林 よしのり
小学館 (2003/09)
売り上げランキング: 46592



あとDVDを一枚を加えて計8点一括発送で注文したんだが、思考する機械コンピュータ1冊だけ先に届いた。

残りの7点は例によって明らかに内容量より大きな箱で届いた。

ダンボールまじ勘弁して。


そんで、2日連続同じドライバーの方に再配達の電話したら2回目は名前だけで持ってきてくれた。

Lucene + TinySegmenterというアイデア


そういえば、TinySegmenterをJavaで実装してLuceneのTokenizerを書けばLuceneで使えるかもね。

実装は比較的ラクだと思う。


今のところLuceneを使う予定はない。ので究極暇になったら作るかも。