2008-03-05 22:17:51

Perl の バイト列→Unicode 処理について

[ Perl ]

ニパターンある

※バイト列の文字コードはUTF8とする。
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use Encode;
use Unicode::RecursiveDowngrade;

my $str = 'utf8';
#my $str = 'ユーティーエフ';

# Pattern A
utf8::decode($str); #これのみだと $str = 'utf8' は素通りされてフラグがたたない
utf8::upgrade($str); #これのみだとフラグはたつが $str = 'ユーティーエフ' は文字化けで戻せなくなる

# Pattern B
$str = decode_utf8($str); # Need use Encode;

if ( utf8::is_utf8($str) ) {
        print "On\n";
}
else {
        print "Off\n";
}
print Dumper($str);

my $rd = Unicode::RecursiveDowngrade->new;
my $strz = $rd->downgrade($str);

if ( utf8::is_utf8($strz) ) {
        print "On\n";
}
else {
        print "Off\n";
}
print Dumper($strz);

ex) http://subtech.g.hatena.ne.jp/miyagawa/20080218
ex) http://blog.livedoor.jp/dankogai/archives/51004472.html
ex) http://subtech.g.hatena.ne.jp/miyagawa/20060820/1156076116

ex2) http://d.hatena.ne.jp/dayflower/20080219/1203493616

2008-03-05 21:54:26

負数の剰余

[ Perl ]

配列の最初の添え字の一つ前は最後の添え字にしてループしたかった。

例:
配列の最後の添え字が 5、今の添え字が x、前に戻る数を y、戻った時の添え字が z
1.x=1,y=2,z=4
2.x=1,y=3,z=3
3.x=1,y=5,z=1
4.x=1,y=8,z=3
5.x=1,y=9,z=2
6.x=1,y=10,z=1
7.x=0,y=1,z=4
8.x=4,y=5,z=4
9.x=3,y=8,z=0

z = (x - y) % 5

ex) http://oshiete1.goo.ne.jp/kotaeru.php3?q=1057715
ex) http://www.hokuriku.ne.jp/fukiyo/math-qa/amari.htm
ex) http://d.hatena.ne.jp/kazusato77/20080121/1200871085
google 電卓は Perl/Pythonと同じ。

JavaScriptはまた違うし、これはハマる。

2007-07-25 22:21:59

Fedora7 perlのリビルド

[ Perl ] [ Linux ]

FedoraのPerlは遅いようだ。
ex) http://buribullet.net/svntrac/buribullet/wiki?p=Fedora%E3%81%AEPerl%E3%81%8C%E9%81%85%E3%81%84%E4%BB%B6

以下を見てリビルドする。
ex)
http://d.hatena.ne.jp/tomisima/20070320/1174407728
http://d.hatena.ne.jp/dayflower/20070320/1174370267

rpmdevtools を初めて知った。

# yum -y install rpmdevtools
$ fedora-buildrpmtree

$ wget http://ftp.riken.jp/Linux/fedora/releases/7/Fedora/source/SRPMS/perl-5.8.8-18.fc7.src.rpm -O rpmbuild/SRPMS/perl-5.8.8-18.fc7.src.rpm

$ rpm -ivh rpmbuild/SRPMS/perl-5.8.8-18.fc7.src.rpm
$ vi rpmbuild/SPECS/perl.spec

@@ -89,8 +89,8 @@
 Patch25:        perl-5.8.8-U27116.patch
 Patch26:        perl-5.8.8-U27391.patch
 Patch27:        perl-5.8.8-U27426.patch
-Patch28:        perl-5.8.8-U27509.patch
-Patch29:        perl-5.8.8-U27512.patch
+#Patch28:        perl-5.8.8-U27509.patch
+#Patch29:        perl-5.8.8-U27512.patch
 Patch30:        perl-5.8.8-U27604.patch
 Patch31:        perl-5.8.8-U27605.patch
 Patch32:        perl-5.8.8-U27914.patch
@@ -316,8 +316,8 @@
 %patch25 -p1
 %patch26 -p1
 %patch27 -p1
-%patch28 -p1
-%patch29 -p1
+#%patch28 -p1
+#%patch29 -p1
 %patch30 -p1
 %patch31 -p1
 %patch32 -p1

リビルド (src.rpm も欲しい場合はオプション -ba)
$ rpmbuild -bb rpmbuild/SPECS/perl.spec

iconv のエラーが出た。
$ which iconv
/usr/local/bin/iconv
$ locate bin/iconv
/usr/bin/iconv
/usr/local/bin/iconv

以前 iconv をソースから入れてた。/usr/local/ 以下のiconv関連を削除した。

再度リビルド
$ rpmbuild -bb rpmbuild/SPECS/perl.spec

以下のメッセージが出た。
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-5.8.8-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-libs-5.8.8-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-devel-5.8.8-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-suidperl-5.8.8-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-CPAN-1.76_02-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-ExtUtils-Embed-1.26-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-ExtUtils-MakeMaker-6.30-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-Test-Harness-2.56-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-Test-Simple-0.62-18.fc7.i386.rpm
Wrote: /home/hoge/rpmbuild/RPMS/i386/perl-debuginfo-5.8.8-18.fc7.i386.rpm

旧rpm削除
# rpm -e --nodeps perl perl-libs perl-devel perl-suidperl perl-CPAN perl-ExtUtils-Embed perl-ExtUtils-MakeMaker perl-Test-Harness perl-Test-Simple perl-debuginfo
# rm -r /usr/lib/perl5/5.8.8
# rm -r /usr/lib/perl5/site-perl/5.8.8

新rpmインストール
# cd /home/hoge/rpmbuild/RPMS/i386
# rpm -Uvh perl-5.8.8-18.fc7.i386.rpm perl-libs-5.8.8-18.fc7.i386.rpm perl-devel-5.8.8-18.fc7.i386.rpm perl-suidperl-5.8.8-18.fc7.i386.rpm perl-CPAN-1.76_02-18.fc7.i386.rpm perl-ExtUtils-Embed-1.26-18.fc7.i386.rpm perl-ExtUtils-MakeMaker-6.30-18.fc7.i386.rpm perl-Test-Harness-2.56-18.fc7.i386.rpm perl-Test-Simple-0.62-18.fc7.i386.rpm perl-debuginfo-5.8.8-18.fc7.i386.rpm

モジュールを最新版に更新
# perl -MCPAN -e 'CPAN::Shell->install(CPAN::Shell->r)'

2007-05-02 15:13:31

CGI.pm の charset('utf-8')

[ Perl ]

CGI.pmのデフォルト文字コードはISO-8859-1。
そこでcharsetメソッドで文字コード指定するが charset('utf-8') は注意。

例1)
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw(-nosticky);

my $cgi = new CGI;
$cgi->charset('utf-8');

my $str = $cgi->param('str') || '';
$str = $cgi->escapeHTML($str);

print $cgi->header,
    $cgi->start_html(-title=>'test',-lang=>'ja-JP'),
    $cgi->h1($str),    #[error] Wide character in print
    $cgi->start_form(-method=>'get'),
    $cgi->textfield('str', $str, 10, 20),    #[error] Wide character in print
    $cgi->submit,
    $cgi->end_form,
    $cgi->end_html;

Wide character in printがログに出力される。
charset('utf-8')だとutf8フラグがparamメソッド取得文字列に付加される。
paramメソッド内で my $utf8 = $charset eq 'utf-8' とキメ撃ちしている事を利用して
$cgi->charset('UTF-8');
と大文字にすれば回避できるが、どうにも気持ち悪い。
仕方なくEncode::encode_utf8でutf8フラグをオフにする。

例2)
#!/usr/bin/perl
use strict;
use warnings;
use CGI qw(-nosticky);
use Encode;

my $cgi = new CGI;
$cgi->charset('utf-8');

my $str = $cgi->param('str') || '';
$str = $cgi->escapeHTML( Encode::encode_utf8($str) );

print $cgi->header,
    $cgi->start_html(-title=>'test',-lang=>'ja-JP'),
    $cgi->h1($str),
    $cgi->start_form(-method=>'get'),
    Encode::encode_utf8( $cgi->textfield('str', $str, 10, 20) ),
    $cgi->submit,
    $cgi->end_form,
    $cgi->end_html;

paramメソッドの時点でUTF8フラグが立つので、$str取得時はEncode::encode_utf8でutf8フラグをオフにする。
さらにtextfieldメソッドがモジュール内部でparamメソッドを使用しているため、textfieldメソッド使用時丸ごとEncode::encode_utf8で括った。

出力前に$cgiを丸ごと Unicode::RecursiveDowngrade とかでutf8フラグ除去するのがよいのか、binmode STDOUT, ":utf8"; するのがよいのか等、もう面倒な事この上ない。
CGI.pmはお気楽なはずだったのに。。残念。
※現時点 CGI.pm 3.29

2007-04-26 00:11:43

YAMLで困ること

[ Perl ] [ YAML ]

タブ使用禁止でスペースのみは慣れる(未だに嫌だが)

こういう時に困る。
my $ftp = Net::FTP->new( '192.168.0.1', Debug => 1, Passive => 1 );
のパラメータ部分をYAMLにすると

Net::FTP:
  - 192.168.0.1
  - Debug
  - 1
  - Passive
  - 1

となって読み辛いし、説明し辛い。コメント(#)必須。

※ , と => は同義語。
ex) http://search.cpan.org/~nwclark/perl-5.8.8/pod/perlop.pod#Comma_Operator___
Net::FTPはモジュール内で '192.168.0.1' をshiftして、残りの配列をそのままハッシュに代入している。

YAMLを直感的に書き辛い時はYAML::Syckで確認。

use YAML::Syck;
use Data::Dumper;
my $ref = {
        net_ftp_opt => [
                '192.168.0.1',
                Debug => 0,
                Passive => 1
        ],
};
my $yaml = YAML::Syck::Dump($ref);
print $yaml, "\n";
my $perl = YAML::Syck::Load($yaml);
print Dumper($perl), "\n";

こういうのが出てくると泣ける(Net::FTP::Commonとか)
config:
  -
    LocalFile: test.dat
    Pass: password
    User: id
  - Debug
  - 1
  - Timeout
  - 120

2007-04-07 15:32:23

Cache::Memcached と DBIx::Class と TT

[ DBIx::Class ] [ Template-Toolkit ] [ Perl ]

"Cache::Memcached と DBIx::Class"の補足。
TT使用時にテンプレート上でDBIx::Classの belongs_to ,has_many 項目は呼び出せない。
理由は上に同じで、キャッシュされていないから。

2007-04-07 12:31:08

Cache::Memcached と DBIx::Class

[ DBIx::Class ] [ Perl ]

Cache::Memcached (Cache::FileCache,Catalyst::Plugin::Cache::Memcachedも) はオブジェクトがキャッシュできる。とても便利。
でもDBIx::Classのオブジェクトは、キャッシュできないことがある。

サンプル:
#!/usr/bin/perl
use strict;
use Cache::Memcached;
use TestDB;

my $memd = new Cache::Memcached {'servers' => [ "127.0.0.1:11211" ]};
my $schema = TestDB->connect("dbi:mysql:testdb;localhost",'user','password');

#OK pattern
my $ok = $schema->resultset('Test')->find(1);
$memd->set('key', $ok);
print $memd->get('key')->message,"\n";

#NG pattern
my $ng = $schema->resultset('Test')->search({id => 1});
$memd->set('key', $ng); #ここでエラー
print $memd->get('key')->next->message,"\n";

$ngはSQL実行結果の値を持っていない。
DBIx::Classのイテレータが素晴らしいのはSQLを最後の最後で実行することだし・・。

↓以下なら動く。Cache::Memcached使用時、イテレータは要注意。

#NG->OK pattern 1
my $ng = $schema->resultset('Test')->search({id => 1})->next;
$memd->set('key', $ng);
print $memd->get('key')->message,"\n";

#NG->OK pattern 2
my @ng = $schema->resultset('Test')->search({id => 1});
$memd->set('key', \@ng);
foreach (@{$memd->get('key')}) {
        print $_->message,"\n";
}

2007-02-28 14:56:24

Image::Magickインストール3

[ Perl ] [ Linux ]

二度目は2007年2月27日で自前サーバ。
Perlのバージョンは、少し前から5.8.8を入れて使っていた。
use Image::Magick する必要のあるアプリケーションをつくってテストすると Image::Magickが無いとエラーが出る。まる一日ハマった。

yumで既存RPM削除
yum remove ImageMagick-perl ImageMagick-devel ImageMagick

ソースインストールする。
wget ftp://ftp.kddlabs.co.jp/graphics/ImageMagick/ImageMagick-6.3.2-9.tar.gz
tar zxvf ImageMagick-6.3.2-9.tar.gz
cd ImageMagick-6.3.2
./configure
make
make install

コマンド
convert aaa.gif bbb.jpg が動作することを確認する

ライブラリのパスを通す
/sbin/ldconfig /usr/local/lib
とか
echo /usr/local/lib >> /etc/ld.so.conf
ldconfig
とか

PerlMagickインストール
cd PerlMagick/
perl Makefile.PL
make
make test
make install

ImageMagickは動作するのに、PerlMagickが動作しない場合
http://cachu.xrea.jp/perl/GetPicSize.html
http://cachu.xrea.jp/perl/ImgResize.html
上記URLを参考にアプリケーション側を変更してもよし。
実際PerlMagickで悩んでいるとき一時的に使って対応した。

2007-02-28 14:55:21

Image::Magickインストール2

[ Perl ] [ Linux ]

CentOS4でも二度ハマった。

一度目は2006年9月でレンタルサーバ。
6.2.5  →  6.2.9と管理会社にアップデートされたのだが use Image::Magick でセグメンテーションエラーが発生するようになりバージョンを戻してもらった。公開サービス上での事だったので心臓に悪かった。

2007-02-28 13:02:14

Image::Magickインストール1

[ Perl ] [ Linux ]

これはよくハマる。

2006年8月にFedora5で、yumでアップデートしたら
use Image::Magick してるアプリケーションが動かなくなった。
セグメンテーション違反だったような・・。
以下のように対応したメモが残っていた。

Fedora ImageMagick(ImageMagick-6.2.5.4-4.2.1.fc5.4)

yum で update
ImageMagick-6.2.5.4-4.2.1.fc5.4

yum で install
ImageMagick-devel-6.2.5.4-4.2.1.fc5.4
↑これがないとmake不能

cpan から install
Image::Magick

[注意]
ImageMagick-perl-6.2.5.4-4.2.1.fc5.4
↑使用禁止(動かない)

2007-01-13 18:00:03

PAR on ActivePerl

[ Perl ]

[ppm4のproxy 設定方法]
DOSプロンプトで
SET http_proxy=http://ipadress:port/

[ActivePerl5.8.8使用時のPAR-Packer]
PAR-Packer-588
http://theoryx5.uwinnipeg.ca/ppms/PAR-Packer-588.ppd
ex) http://beta.nntp.perl.org/group/perl.par/2007/01/msg2783.html

[ppm4でCUI]
ppm-shell

2007-01-12 19:00:05

LWP::UserAgent::WithCache

[ Perl ]

http://search.cpan.org/~sekimura/LWP-UserAgent-WithCache-0.03/
レスポンス304時の、本来Cacheが返ってきて欲しいところで、contentが空で返ってくる。
ハマった。

http://rt.cpan.org/Public/Bug/Display.html?id=16377
にある以下のパッチを適用。
--- WithCache.pm (revision 9476)
+++ WithCache.pm (working copy)
@@ -36,7 +36,7 @@
if ( defined $obj ) {

# XXX: return cached response before "Expires"
- if (defined $obj->{expires} and $obj->{expires} > time()) {
+ unless (defined $obj->{expires} and $obj->{expires} <= time()) {
return HTTP::Response->parse($obj->{as_string});
}

解決。

2007-01-02 20:18:10

XML::Atom::Simple

[ Perl ]

文字コードが us-ascii 固定?
そりゃねーよ、と。

2007-01-02 20:17:30

Atom Feed

[ Perl ]

XML::Atom より XML::Atom::Simple がよいかも

2007-01-02 20:16:25

utf8フラグ落とし

[ Perl ]

XML::Atom 使用時は必須

use Encode;
$xml = Encode::encode("utf8", $xml);

文字コードutf8キメうちならば
$xml = Encode::encode_utf8($xml);
もしくは
utf8::encode($xml);

参考)
http://jp.rubyist.net/PerlMa/wiki.cgi?page=20060401-BundledLibraries