日記帳だ! with Tux on Libserver

二度目の大改造!! 日記帳…か?を継承し、より柔軟でパワフルなBlogに変身しました。

RSSに対応しています。リンク・コメント・トラックバックは自由にしていただいてほぼ問題ありません。
RSS購読方法、僕のリンク・コメント・トラックバックについての考えを読むことをおすすめします。

JavaScriptを有効にし、Cookieを受け入れ、以下のブラウザを使うことで完全なコンテンツが楽しめます。
Mozilla Firefox 3.0(Get Firefox)・Opera 9.6・Safari 3.2・Lunascape 4/5(Gecko)・Lunascape 5(WebKit)
Internet Explorer 7/8とそれを使うIEコンポーネントブラウザ(Lunascape・Sleipnirなど)

<< 過去

RubyのよいところをIronRubyで使う

IronRuby 1.0が出てたので遊んでたのだが、IronPythonより扱いいいですね。

IronRubyは以前IronPythonで遊んでたが、当時はDLRも完成してなかったので遅かった。(参考記事 : IronRubyを試してみる)

その上IronRubyはBetaで、IronPythonはPythonの文法になれることが出来ずあまり使ってこなかった。

やはりC#でガリガリが多かった。


だが今はDLRも完成しとても早くなった。これは実用に耐える。

ただC#で言うところのusingがブロック付きメソッド呼び出しでできなかったり、

デリゲートを取るメソッドをブロック付きメソッド呼び出しでデリゲートを与えられなかったり、

ちょっと残念ですね。まぁそのあたりは難しいですからね。


しかしRubyはその残念さを解消する方法を持っている。

module System::IDisposable
  def using
    begin
      yield self
    ensure
      self.Dispose
    end
  end
end

よく考えたらこんな不気味なこともRubyでは書けてしまうんだよな。

System::IO::StreamReader.new('C:\work\hoge.txt').using{|f| f.ReadToEnd }

ブロック内で例外が投げられても必ずDisposeされる。


まぁそんなわけでIronRubyでいろいろ実験してたのだがRubyのクラスの.NETでの型名が興味深かった。

Rubyのクラスはclassメソッドで、.NETの型名はGetTypeメソッドで得られる。

  • Fixnum → System.Int32
  • Float → System.Double
  • BigNum → Microsoft.Scripting.Math.BigInteger
  • String → IronRuby.Builtins.MutableString
  • Array → IronRuby.Builtins.RubyArray
  • Hash → IronRuby.Builtins.Hash

Fixnum・Floatはプリミティブ型で表現されているね。ちゃんと考えてあるね。

あと驚いたのがBigNumはDLRで用意されてるみたいね。こんなものがあるのか。

StringはIronPythonではSystem.Stringらしいが、Rubyではupcase!メソッドとかで変更が出来るのでMutableなのを自前で用意したよう。

とはいえIronRubyで使うなら不便は少なくて、RubyのStringは適宜System.Stringに変換されるし、System.Stringも破壊的メソッドが使えない以外は同じように使える。

Array・Hashあたりのデータ構造は型の概念がないから別に作ってるだけの気がする。

それならSystem.Collections.ArrayList・System.Collections.Hashtableでもよかったきはするが。


Rubyと.NETは違うものだから同じようなものでも別に用意したりしているが、

逆にRubyらしいものが.NETで使えることになる。

まずRubyらしいものだが、Enumerable#injectですね、これがSystem.Collectiuons.IEnumerableを実装していれば使える。

a=System::Array[Fixnum].new(10)
(0...a.Length).each{|i| a[i]=i }
p a.inject(0){|s,i|s+i}

すばらしい!


早くなったIronRubyでGUI作ってみるのもいいかもね。

ただIronPythonのときに思ったが手書きでGUI開発はけっこうめんどくさいのよね。

WPFを使うとかすればいいのかも知れんが、まぁそれは後の課題と言うことにしよう。

GUIだけIDEで開発して、後は具体的にIronRubyで書いていくのもよさそうだ。


Author : hidemaro
Date : 2010/05/15(Sat) 23:58
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

Rubyのキーワード begin・rescue・else・ensure・end

英語の授業でmoodle言うCMSを使っている。主にReadingの練習用です。
"many many many many write!"なんて言ってますけど読むことも大切ですねって。
読み物が置いてあって読むわけですが、まぁいままで読んでたのはまぁまぁ簡単だったのよね。
読んでそれについてのQUIZに答えると。まぁ大体70%ぐらいは正解しますね。ほとんど正解なんてときもある。
宿題で今学期の目標分進めておきましょうとか書いてあったので家からやってたんですが、
その読み物を読み終わったら"TOEFL"と書いてあって、TOEFLの何だろうと思ったらTOEFLの問題文だった。
そしてQUIZはTOEFLの問題。やったが難しい。1回目の正解率40%でこのQUIZの合格ラインの60%越えないわ。
その問題だが、この文章にはなんて言う題名が合いますか?とか、ここから類推できるのはどれですかとか。
これ国語のテストみたいですね。事実英語圏の人が受けても4択なのに中ぐらいの点数しか取れないんだと。
ちなみにTOEFLは大学の留学のための英語力をチェックするための試験です。
そこでensureとかなんとか書いてあって調べたら「確実にする」とかいう意味だった。
なんかで見た言葉だなと思ったらRubyの例外処理用のキーワードですわ。
普通例外処理用のキーワードというと try~catch~finallyですよね。
C#の場合このように書きます。
try{
System.IO.StreamReader sr=new System.IO.StreamReader("foobar.txt");
try{
data=sr.ReadToEnd();
}finally{
sr.Close();
}
}catch(System.Exception e){
System.Console.WriteLine("Catch! {0}",e);
}
tryしてcatchでその例外をキャッチすると。
ここではSystem.Exceptionでキャッチしてるが、System.IO.IOExceptionとかでキャッチするとそれ以外は無視する。
catchは何個も連ねて書いていいのでこのときはこうという風に条件分岐ができる。
finallyは必ずストリームを閉じるとかそういうことを忘れないようにという使います。
ただしC#の場合はusing構文を使うのが普通ですが。
  using(System.IO.StreamReader sr=new System.IO.StreamReader("foobar.txt")){
data=sr.ReadToEnd();
}
IDisposableを実装したオブジェクトなら自動的に破棄できると。
usingを使う癖を付けておきましょうとよく言われます。
しかしRubyは違う。
begin
fh=File.open('foobar.txt')
begin
fh.each do |line|
print line
end
ensure
fh.close
end
rescue => e
p e
end
Rubyではbegin~rescue~else~ensure~endという構文を使います。
まつもとさん曰く、試してして失敗をキャッチするというよりかはなんかあったときレスキューに行くというほうがいいよね。
とどこかに書いてあったような気がするんだがなぁ……
まぁいいや、とりあえずキーワードが違うんです。
beginから始まることについて、例外がraise(throwではない)されればrescueに行き、何もなければelseに行く。
そしてどちらにせよ最後はensureに行くという構造をしている。
rescueでは rescure => eと例外について受け取る変数を指定したり、 rescue Errno::ENOENT のように例外を限ることもできる。
上の例ではelseは使っていない。
もっとも上の例について言えば、入れ子になってる begin~ensure~endは、
  File.open do |fh|
fh.each{ |line| print line }
end
のようにFile.openをブロック付きメソッド呼び出しすればいいんですけどね。
このRubyのそれの言葉の意味を考えると、
rescue : 例外来たら駆けつけるよ
else : 例外なく終えてしまったなら……
ensure : ここにあることは確実に実行されます
という風な意味でしょう。ここにあるelseってのはしっくりきませんけどね。
rescueで楽しいことはretryっていうのがあるんですね。これしたらbeginからやり直すことができる。
自転車がパンクしたってrescueに応急修理すればretryすればいいじゃない。
そして家に着いたらensureで確実に点検しましょうよ。なかなか自然だと思います。
いいキーワードだと思います。
が……問題は\try~catch~finallyというキーワードがあまりに有名なので混乱せんかということだ。
あとthrowがraiseだったり。厄介なのはthrowに別の意味あったりする。
同じようなことはPerlにも言えますけどね。Cで言うところのbreak,continueがlast,nextだったり。
Rubyでもnextは使われていますね。
まぁ慣れてしまえばそっちのほうがいいのかもしれんが、慣れるまでは大変そうです。
Author : hidemaro
Date : 2009/07/31(Fri) 23:28
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

含まない正規表現の罠

ある文字列を含まない正規表現について調べるとPerlでは(?:(?!foo).)+とある。
fooの部分には任意のパターンが来ることができる。
時々このパターンは便利で、例えばJR○○駅のうち、JR難波駅以外というのは、こういうパターンで書ける。
JR(?:(?!難波).)+?駅
まぁこんな調子で抜き出すことができる。
まぁ便利な正規表現です。
ところが調べていたらこんな欠陥が浮かび上がってきた。
というのもgankaiという文字列を含まないパターンを作ってこう調べた。
print join(',' , 'gankai'=~m/(?:(?!gankai).)+/g),"\n";
するとankaiとヒットする。確かに正解です。
けど直感的にはgankaでもいいように見えますね。
普通は頭からマッチさせていってマッチしたらそれで進めて行くという風になっています。
いくら正規表現が欲張りだからってマッチしたものを破棄してまで進めたりはしない。
なのでgankaになると思ったのですが、実際にはgから始まらず次のaから始まっている。
さらにこういうのも調べてみた。
print 'gankai'=~m/^(?:(?!gankai).)+/ ? "Hit!" : "None!";
さっきのことが本当か、先頭からマッチさせてマッチするか調べた。
するとマッチしないという。gから始まるのでは何かがだめらしい。
そこで調べて気付いたのだが、実は(?!~)っていう拡張正規表現の意味は後ろにマッチするものがないという意味らしい。
Perlの拡張正規表現には先読みと後読みという機能がある。
先読みというのはこれから読むところを先にチェックすること。
後読みというのは既に読んだところを改めてチェックすること。
例えば豚(?=肉)とすると、肉が後ろに続く豚という文字列にのみマッチする。
このように後ろにある後で読もうとすることを先にチェックすることを先読みというわけ。
逆に(?<=豚)肉とすると、豚が前に来る肉という文字列にのみマッチする。これが後読み。
このうち先読みを活用したのがさっきの正規表現。
(?=xxx)はxxxに後ろがマッチする、(?!xxx)はxxxが後ろにマッチしないという正規表現。
そして(?:(?!gankai).)+の意味を解くと、
gankaiという文字列が後ろに続かないところにある1文字にマッチするというパターンが1回以上つづくという意味。
gankaiという文字列については、gの前でgankaiという文字列が後ろに続かないという条件を満たさないので、
1文字目のgからマッチが始まらないと言うこと。その次のaの字の前から見ればgankaiという文字列はないので問題なし。
nの前にも…そして最後にiを読みとって終わり。
そのためさっきのような問題になったわけですね。
じゃあ後読みを使えばいいのかというとそういうわけでもないでしょう。
後読みの場合もそれまでにその文字列を読み取っていないかだけのチェックですから。
だから正規表現ではその文字列を含まないパターンを作るのはきわめて難しいと。
まぁ簡単なパターンを組み合わせて長い長いパターンを作るという手もあるけど。
まぁ確実なのはこんなパターンですけど。
(.+)(?(?{$1!~m|gankai|})|(?!))
ようは読み取った部分がマッチしなければいいんですよ。
コードを埋め込んだ全知全能の正規表現の記事で取り上げたとおりにそれを書きました…
けどクラッシュしました。まぁ無茶ですね。
なかなかままならないものです。
まぁ一般的には(?:(?!xxx).)+というパターンは問題ないように思います。
けどこういう問題も実は存在すると言うことを忘れてはならないと思う。
僕も今日初めて気付いたけど(?!xxx)っていうパターンは含まない文字列専用じゃないということ。
それを忘れないで欲しいですね。
それさえ分かってれば結構納得のいく話だと思います。
だって含まない文字列専用ならなんでこれと他のものを組み合わせて(?:(?!xxx).)+なんて書かないといけないのか納得いきませんからね。
これも工夫です。
Author : hidemaro
Date : 2009/05/24(Sun) 23:10
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

何の役に立つのtap、こんな役に立つのtap

RubyのObject#tapをちょっと試してみた。
ちょっと面白いメソッドなんですよね。
Ruby 1.8.7以降から使えるようになったはず。
ところでinjectについて整理してみるとこういうメソッドであると。
s=0;
(1..100).each{|i| s=s+i }
puts s
puts (1..100).inject(0){|s,i| s+i }
上3行と同じ事がinjectですね。
このeach内部のs+iの部分を自由に置き換えてやれるのがinjectです。
ただこのs=って部分が邪魔になることもあるんですね。
例えばハッシュに要素を追加していくことをinjectで書くこと。
h=Hash.new(0)
('a'..'z').each{|x| h[x]+=1 }
p h
p ('a'..'z').inject(Hash.new(0)){|h,x| h[x]+=1; h }
h=(h[x]+=1)ではまずいんですね。だって返り値は代入した値だから。
だからその後にhを評価して返り値をhにするという措置が必要になると。
これは無駄だよねというのは確かですね。
ただこれってinjectに向かないことなのは確かです。だってinject使わなきゃこんな小細工いらないんだし。
そこでtapの話が出てくるわけです。
そもそもinjectだってsって変数があればいらないんですよ。
このsを用意して、sを加工して、最後にsを使うっていうのを1行で書きたいからinjectするんです。
じゃあ、sを用意して加工して最後に使うという加工の部分をもっと一般的にしないなってのがObject#tapですね。
p Hash.new(0).tap{|h| ('a'..'z').each{|x| h[x]+=1 } }
このtapってのはそれを加工してその結果を返すというメソッドです。
実例と見せられないと何のことかわからないメソッドですよね。
こんな風に使います。
しかしそこまでして1行で書きたいかっていうのは確かな話ではありますけどね。
ただ1行プログラムって結構愛されてるんですね。そのための道具であるinjectがあんなに流行ってるってだけでわかることです。
だからtapも使われるんじゃないかなと思いますよ。
あとtapの使い道ですがオブジェクトが流れていく道に取り付けるなんていうのもあります。
puts (1..10).map{|x|x**2}.tap{|x| p x }.inject(:+)
mapの結果を確認したいが、どうすればいいだろうかって時に使えます。
tapってのは別にそのオブジェクトの内容を変えなければそのまま抜けていくだけですし。
こんな風に見るだけとかいうときには十分使えます。
あとこんな風にも使えます。
puts (1..10).map{|x| (x**2).tap{|y| p y} }.inject(:+)
これもさっきと似てるけど、こんな風にmapなどの中に埋め込んでもいいです。
何がいいっていらなくなったらtap部分を取り外すだけでいいってところですね。
そういうデバッグツール的な使い方もできます。
1行プログラムのデバッグしにくさが取り除けていいですね。
なかなか楽しいと思います。
こういう役に立たなそうなメソッドを導入しようと考えた人は賢いなと。
Author : hidemaro
Date : 2009/05/06(Wed) 23:15
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

音楽の統計を取るPerlロボット

実験で測定したのはショットキーバリアダイオードの逆方向特性であることが発覚。
まさか逆方向電圧とは。どうもショットキーバリアダイオードは逆方向電流が大きいらしい。
そして実験で半導体に金属を接合させて作ったあれはショットキーバリアダイオード×2だったのか。
いや恐ろしいものを作ってしまった。
本当はオーミック接合(すなわち普通の電極)を作る実験だったみたいですけどね。
まぁいいや。オーミック接合もショットキー接合も兄弟みたいなもんなんだし。
さて、今日はおもしろいCPANモジュールを発見した。
Audio::WMAというやつなのですが、これはWMAのタグ情報を解析してくれるというもの。
これは読みこみ専用です。
便利そうですね。これで統計を取ってみました。
use strict;
use warnings;
use Audio::WMA;
use utf8;
binmode(STDOUT,':encoding(cp932)');

my $dirname='C:\Music';
Audio::WMA->setConvertTagsToUTF8(1);
opendir(my $dir,$dirname);
my %list=();
while(my $name=readdir($dir)){
next if $name!~m/\.wma$/;
my $curwma=Audio::WMA->new("$dirname\\$name");
my $artist=$curwma->tags->{'AUTHOR'};
$list{$artist}//=[];
push(@{$list{$artist}},$curwma->tags->{'TITLE'});
}
closedir $dir;
for( sort{ @{$list{$b}}<=>@{$list{$a}} || $a cmp $b }(keys %list ) ){
print '"'.$_.'",'.(@{$list{$_}}+0)."\n";
}
今回はuse utf8;してやります。
それでbinmodeで普段ならSTDOUTをshiftjisとしているところを今日はcp932としています。
本質的な所ではないのですが、Shift_JISとCP932で文字の対応が少々違うんですね。
それでUnicodeからShift_JISに変換するときに対応する文字がないと言われることがあるんですね。
Windows環境においてはCP932の方が安心です。日本のWindowsで使える文字は基本的にはCP932に入ってる分だし。
use utf8;したらAudio::WMA->setConvertTagsToUTF8(1);としましょう。
これで日本語も安心です。しないとなんのことかわからないし。
それで1つ1つのファイルについてnewでオブジェクト作って解析します。
infoメソッドでは情報の入ったハッシュリファレンスが得られる。
ハッシュリファレンスの内容はplaytime_secondsに再生時間が入っていたり、bitrateにビットレートがビット単位で入ってたり、
というところです。今回は使いませんでした。
もう1つがtagsメソッドで、これではタグの情報がハッシュリファレンスで得られます。
TITLEにタイトル、AUTHORにアーティスト名なんてところです。ファイルによっては詳しく入ってるのもあるかも。
結構めんどくさい処理なのでPerlでできるようになるのはありがたいですね。
MP3にも同様の道具があるはずですが詳しくは調べていません。
まぁPerlなので何とかなるでしょう。
そういえばAudio::WMAってPurePerlらしいですよ。
驚いたけど、XS使うよりもPurePerlの方がかえって楽かもね。
PurePerlならコンパイラないとかいう心配はないですしね。perlとmakeだけあればいけるはず。
Author : hidemaro
Date : 2009/05/04(Mon) 23:39
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

コードを埋め込んだ全知全能の正規表現

11の倍数を発見する正規表現というのは書けるだろうか。
そんなもんいるのかというのは置いておいて、
作れるかどうかでいうと、Perlでは案外簡単に作れてしまいます。
えらいもんですね。
まずパターン中にコードを埋め込めるんですね。
m/(?{print "X"})/
何のことかわからないが、とにかく(?{~})の中は実行されると言うこと。
これを使ってやります。といってもこれだけでは駄目なんですが。
これとこういうパターンを使います。
(?(条件)真の時|偽の時)という風なパターンがあるんですね。
条件は(?{~})を使ってコードで書けると。
それともう1つ使えばできます。それは(?!~)ってパターンです。
これは~の文字列を含まない文字列というパターン。
実は含まない文字列のパターンってむちゃくちゃめんどくさいんですよ。
けどこれを使えば簡単なんですね。(?:(?!foo).)+とかするだけです。
これの~部分に何も入れない(?!)ってパターンは何にもマッチしないという意味らしい。
これらを使って(?(?{$1%11==0})|(?!))っていうのを$1をキャプチャするところの直後に入れると、
$1%11==0を満たさないとき(?!)ってパターンが入ってドボン。
という仕掛けになってるわけだ。
というわけでこれを使って11の倍数を検索してみた。
print join(',' , '22597619494114889245'=~m/(\d+?)(?(?{$1%11==0})|(?!))/g),"\n";
すると、22 , 597619 , 94114889と出てきます。うまいこといってますね。
この程度なら極端に遅いなんて事もありません。
これの使い道ですが、例えばIPv4のIPアドレスにマッチするするパターンとかね。
m/(\d{1,3})(?(?{$1<256})|(?!))\.(\d{1,3})(?(?{$2<256})|(?!))\.(\d{1,3})(?(?{$3<256})|(?!))\.(\d{1,3})(?(?{$4<256})|(?!))/
各桁の数字は1桁から3桁だけど、3桁は3桁でも256未満ということでこういう風に条件を埋め込めると。
もちろんこの場合はガリガリ書けば256未満のパターンをこんなの使わなくても作れますけどね。
けど意味がわかりにくい。けどこれなら一目瞭然ですよね。
いや知ってればですけど。けど$1<256っていう制約があるんだなってわかりそうなもんだ。
こういう正規表現あってもいいと思ってたけど、さすがPerlやってくれますね。
Perlのマッチはかなり柔軟だと思います。
PHPでは置換でコールバック関数使うときは特別の置き換え関数を使ったけど、
Perlの場合はeオプションつけるだけですからね。
さすがだなと思いますけど、これPerl以外で通用するのか?
それだけが心配なところです。Rubyではそのまま打っても通用しなかったからね。
また調べてみることにしよう。
Author : hidemaro
Date : 2009/04/29(Wed) 23:23
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

Unicodeにこだわるからか、うまくいかない

ええ加減散髪に行ってきた。
これでもかってぐらい切ってもらった。
同じ値段でやってもらうのが申し訳ないぐらい切ってもらった。
まぁ先延ばししてきて髪の毛がすごい伸びてやっと散髪にいくというのはひどいですが、
しかしすっきりしたのでこれでよしとしましょう。
そういえば今日はエイプリルフールか。冗談を言う日ではあるけれど、
しかしそんな日になにやら真面目に発表するところもあるわけだしね。
だからエイプリルフールに便乗した行動は、必ずしも冗談じゃないのだよというのは最近思うところですね。
URLで使える文字はRFC3986によれば数字・アルファベット・ハイフン・ピリオド・アンダースコア・チルダらしい。
これ以外の文字は%E5などして表示する必要があると。
PHP使ってるとこの辺は自動的に考えてくれるので、あまり気にしなくていい。
ただ受け取った文字列のエンコーディングはわからないので、内部で使ってるエンコーディングに統一する必要があるが。
しかし受け取るのもUTF-8、使うのもUTF-8なら気にすることはないでしょう。
作るのはurlencode関数でできるそうだ。
Perlでこれをやるには正規表現で置換するのが普通ですね。
my $x='%83R%83%93%83Z%83%93%83g%82%a9%82%e7%89%ce%82%aa%95%ac%82%a2%82%bd';
$x=~s/%([0-9A-Fa-f]{2})/pack('C',hex($1))/eg;
print $x;
ここではuse utf8;の類はしないで、Shift_JISで出力すれば端末で見れることを考える。
有名な方法ですね。
ただ以前pack('C',hex($1))はかなり無駄に見えるからchr(hex($1))と書く方がよいのではというのを見たことがある。
僕もそれには賛成ですね。というわけで以下はそんな風に書きます。
まぁPerlでCGI作るわけでもないのでこれだけなら記事にすることではないのだが、
ただこれが思惑通り行かないこともあるんですね。
それがuse utf8;の類を使ったときですね。
use encoding 'shiftjis';
use Encode;
binmode(STDOUT,':encoding(shiftjis)');
my $x='%e3%83%9e%e3%83%b3%e3%83%9b%e3%83%bc%e3%83%ab%e3%81%8c%e5%90%b9%e3%81%a3%e9%a3%9b%e3%82%93%e3%81%a0';
$x=~s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg;
print decode('utf8',$x);
use encoding 'shiftjis';とエンコーディングがShift_JISであると示す。
そうすると急にうまく行かなくなる。
use utf8;なら問題なくいくことも多いけど、まぁたまにうまくいかないときもある。
実はそうもプログラムは間違ってないんですよ。
このあたりがuse utf8;の難しいところです。
use utf8;の類を宣言すると普通は文字列にUTF-8フラグというのが立つ。
これは文字をUnicodeで表しておくするモードですね。
print ord('田');としたとき、Shift_JISの環境ならば普通は147と出てくる。
というのも'田'は0x93と0x39の2バイトで表される。その1バイト目は0x93、10進数に直すと147となるわけだ。
しかしuse utf8;の類をすると、この結果は30000となる。
このときは田というのは0x7350と記録されているわけだ。その1文字目の0x7350を10進数に直すと30000と。
その違いがかなり厄介なんですね。
というのはこの置換のとき、%e3というのを発見したら、chr(hex('e3'))に置き換えるわけだが、
これが厄介で、use utf8;してるとUnicodeの0xE3に置き換えてしまう。
UTF-8フラグ自体はこうやったら外せるんですね。
$x=encode('utf8',$x);
しかしこれで外したところで状況が改善されるわけでもない。
一体どうなっているのだろうか。
やはりこういうことはUTF-8フラグをつけないのがよいのだろうか。
use strict;
use warnings;
use encoding 'shiftjis';
use Encode;
binmode(STDOUT,':encoding(shiftjis)');
my $x;
{
no encoding 'shiftjis';
$x='%e3%83%9e%e3%83%b3%e3%83%9b%e3%83%bc%e3%83%ab%e3%81%8c%e5%90%b9%e3%81%a3%e9%a3%9b%e3%82%93%e3%81%a0';
$x=~s/%([0-9A-Fa-f]{2})/pack('C',hex($1))/eg;
}
print decode('utf8',$x);
とりあえずこうすればうまくいくようになった。
しかしどうしたものかな。全部Unicodeというのも困ったものだ。
Author : hidemaro
Date : 2009/04/01(Wed) 23:39
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

そうも役に立たなそうなtieを活用してみた

ちょっと面白いものを見つけた。
perl - Tie::Expression (404 Blog Not Found)の記事で取り上げられてるTie::Expressionですね。
ところで小飼弾さんは妙に有名ですね。
Perlの世界においてはEncodeモジュールの元になったJcode.pmの作者ということで有名なのね。
まぁ何かと有名な方ですが、その方が作ってしまったパッケージの話。
実に短いがちゃんとCPANにあるんですよ。
CPANでTie::Expressionを入れてみた。使い方はこう。
use Tie::Expression;
tie %_,'Tie::Expression';
print "料金は$_{100*50}円です。\n";
以前@{[ ]}を使えば""の中に式を埋め込めるという話題を出した気がします。
ただどうもめんどくさいと。そういうわけで考えられた話です。
そこで特殊なハッシュ%_を作って、それの機能を使って実現してるわけ。
それでtieとか使って作った%_というのはいかなるものなのか、
というのを説明しようとすると実に難しい。
tieというのは変数の裏にオブジェクトを隠した変数を作る関数。
tie %_,'Tie::Expression';  # $obj=Tie::Expression->TIEHASH();
#以降に示したようにオブジェクトを裏で作ってるわけだ。
それで要素の参照を裏で次に示すように読み替えて実現すると。
my $x=$_{$foo};  # my $x=$obj->FETCH($foo);
$_{$foo}=100 # $obj->STORE($foo,100);
delete $_{$foo}; # $obj->DELETE($foo);
tieの裏で起きてることの一部をここに書いてみた。
こんな風にできるオブジェクトを作ればいいと。
このTie::Expressionというのは、FETCHすると、キーとして与えたものをオウム返しするだけのオブジェクト。
これによって@{[ ]}のように""の中に埋め込むのに活用できると。
なるほど、というわけでこれをマネしてTie::Printfというのを作ってみた。
use Tie::Printf;
tie my %f,'Tie::Printf';
print "U+$f{'04X'}{30000}\n";
$f{'04X'}とすると、キーを与えたらそれをsprintfで%04Xというフォーマットで文字列化したものを返すようにtieした、
ハッシュリファレンスを返すようにして、$f{'04X'}->{30000}と使うと。
ちなみにPerlでは[ ]または{ }にはさまれた->は省略できるので上のようにかけると。
そういえばちょっと友人とカリー化って何?というような話で盛り上がったのだが、
あれは関数が1つしか引数を取れない世界で2つ以上の引数を与えたいとき、
1つ目の引数を与えたら2つ目の引数を受け取って結果が出る関数が帰ってくるというようにして、
2つ以上の引数を受け取れるようにするというものなのね。
それそのものだよね。1つ目の引数であるフォーマットをキーとして与えると、
2つ目の引数である値をキーとして受け取り、sprintfされた文字列を返すハッシュリファレンスを得ると。
まぁ案外驚くことのない工夫なのかもしれません。
それで作ったPrintf.pmを貼ってみる。
use strict;
use warnings;
our $VERSION='0.80';
package Tie::Printf;
sub TIEHASH{
my $pkg=shift;
my $f=shift;
return bless(\$f,$pkg);
}
sub FETCH{
my $self=shift;
if(!defined $$self){
tie my %f2,'Tie::Printf',shift;
return \%f2;
}else{
my $format=$$self;
my $out=shift;
return sprintf("%$format",$out);
}
}
sub STORE { undef }
sub FIRSTKEY{ undef }
sub NEXTKEY { undef }
sub DELETE { undef }
sub CLEAR { undef }
1;
引数に何も与えなければさっきのような%fにtieできて、
引数を与えればキーをフォーマットに沿ってsprintfしたものを返すハッシュにtieできると。
まぁそんなところです。
しかしtieというのはそうも面白くない。
まぁまぁハッシュにtieするのは楽しいかも知れないけど、
面白くないのは配列にtieすること。
やはり配列にtieできるとなれば無限数列とか作りたいけど、
どうしても通常の配列と同様の性質を持たなければならないのでそんなものは作れない。
また面白くないのはtieしたものは、ただのハッシュやら配列と性質が変わらないと言うこと。
例えばこういうことはできないと。
%foo->bar(100);
普通のハッシュにbarというメソッドを加えるなんてことはいかにtieしたものでも無理だと。
まぁPerl 5のオブジェクト指向はそれなりに役に立つものであるけれど、
やはり元々そう考えてこられたものと比べると見劣りしてしまう。
いろんなオブジェクトがforeach出来たら楽しいよね、
.NET FrameworkではSystem.IEnumerableを実装すればなんでもできる、
Rubyではeachというメソッドを用意すればEnumerableをincludeしてやればreduceさえできる。
別にそれが配列と同じような性質を持ってる必要はないわけで、いろいろ自由にできる。
さらにいうと添え字を使うことも.NET Frameworkの場合インデクサ( this[int i]のような特殊なプロパティ )、
Rubyの場合は[]演算子、[]=演算子のオーバーロードでできると。
Rubyは違う世界だから事情は違うけど、キーを取ってなんかするオブジェクトを作りたければ[]演算子をオーバーロードするだけなのね。
けどPerlにそれはない。ただ非力なわけじゃないから、以前書いたようにイテレータでいろいろできる。
ただ全くないわけじゃなくてtieはありますね。tieすればキーを得ることができると。
ただそうも役に立たんなぁと。それはさっき言ったように普通のハッシュ以上でも以下でもない能力しか持てないから。
どちらかというと、普通の変数に読み取り専用とか、そういう特殊な性質をつけるための道具なのかなと。
全く新しく作ったオブジェクトに配列に似た機能も与えようとか、そういう道具ではなさそうだと。
本当に惜しいなぁと。
まぁそんな道具をちょっと変な使い方をしてみたというお話でした。
Author : hidemaro
Date : 2009/03/26(Thu) 23:07
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

evalブロックをuseでも活用するんだ

Perlにはevalブロックというのがある。
普通evalというと文字列で与えられたコードを実行するというものですけどね。
eval 'print $x+$y;';
これとは似て非なるもの。確かにこれと同じ事はできるのだけどね。
evalブロックは、違うものだがC#とかJavaとかのtry~catch構文のようなもの。
my $x=<>; chomp $x;
my $y=<>; chomp $y;
my $z;
eval{
$z=$x/$y;
1;
} or do{
print "Error : $@";
exit;
};
print "$x/$y=$z\n";
Perlのプログラムを動かしてると途中で死んでしまうことがある。
けどevalブロックの中で動かしてると、evalブロックの返り値が空リスト、すなわち偽になるだけで、プログラム自体は死なない。
最後まで処理を終えたときの返り値が真になるようにしておけば、死んだときはorなどでエラー処理ができる。
エラーの情報は特殊変数$@に入る。
そういう利点があります。
まぁあんまり使うところはないのですが、パッケージの読みこみ時にパッケージが無かったときの処理を入れられるといいなと。
例えばList::MoreUtils::minmaxを読み込めればそれを使い、
そうでなければList::Utils::minとList::Utils::maxを別々に使うとか。
まぁそういう選択があってもよいのではないかということです。
それにuseのときに死んだら、"Can't locate List/MoreUtils.pm in @INC"とかいう微妙な表示でしょ。
どちらかというと、"List::MoreUtilsが必要です。導入してください。"の方がうれしい。
まぁこういうことができてほしいということです。
しかしこんなの簡単だろと。
eval{ use NoPackage qw(foo bar); 1; } or die '親切なメッセージ';
これでいけるんじゃないかなと。
しかしそうなる前に死んでしまった。あらー、なんでだろ。
調べるとuseというものはこれと等価らしい。
BEGIN{
require NoPackage;
import NoPackage qw(foo bar); # NoPackage->import( qw(foo bar) );
}
このBEGINブロックというのは、コンパイル時に実行されるものらしい。
そのためevalブロックとして実行される前にuseは実行されて、そこで死んでいると。
これはrequireでモジュールをロードすることと、importで必要に応じてインポートしてもらうこと。
実は#以降に書いたことと一緒です。そのためimportというメソッドを用意して、
これの第一引数にnew同様パッケージ名が来ることだけ考えておけば、
インポート以外のためにもuseのとき渡すリストは活用できるようです。
このimportというのは特殊な関数じゃなくて、そのパッケージのimportメソッドを呼び出しているに過ぎないわけね。
このような表記法はimportやnewに限らずなんでもいける。uniqでもいけます。
my @a=uniq List::Util qw(foo bar foo List::Util);
#List::Util::uniq('List::Util' , qw(foo bar foo List::Util) )
print join(',' , @a) , "\n";
まぁそれはともかく、必ずしもコンパイル時に実行しなければならないものでもないから、
こうすればOKです。
eval{
require NoPackage;
import NoPackage qw(foo bar);
1;
} or die '親切なメッセージ';
こうすると親切なメッセージを吐いて死ぬ。
ところでこんな風になった理由はevalブロックの中身も始めにコンパイルしているからで、
文字列をevalした場合はこうではない。
eval 'use NoPackage; 1;' or die '親切なメッセージ';
特に問題なく動く。この場合はevalを実行するときになってコンパイルするから。
けどこんな風に途中でevalを入れるのは効率が悪いらしい。
あとコンパイル時にエラーに気づけなかったり。
というわけなのでevalブロックの方が都合がいい。
ちなみにuseできなかったときは別にサブルーチンを定めようというのなら、
そのサブルーチンを定める部分は文字列でコードを与えるevalを使う必要がある。
というのもサブルーチンの定義ってコンパイル時にやるみたい。
だからサブルーチンの宣言よりも前に使うことができたりする。
そんなわけでこれを応用して作ってみた例。
eval{ minmax(1,6,7,5); } or print "miss\n";
eval{
require List::MoreUtils;
import List::MoreUtils qw(minmax);
1;
} or eval <<'EOF';
sub minmax{
#print "Call pure perl\n";
my ($min,$max);
$min=$max=shift;
while(@_){
my ($minelem,$maxelem);
$minelem=$maxelem=shift;
if(@_){
my $elem=shift;
if($maxelem < $elem){ $maxelem=$elem; }
else { $minelem=$elem; }
}
$min=$minelem if($min>$minelem);
$max=$maxelem if($max<$maxelem);
}
return ($min,$max);
}
EOF
my ($min,$max)=minmax(6,8,15,7,3,10,5,10,4,9);
print "min : $min\nmax : $max\n";
minmaxの定義をevalブロックでやると、それより前のevalでminmaxを実行しているところでも、
ここで作ったPerl版minmaxが動いてしまう。というわけでコードを文字列で与えると。
これでList::MoreUtilsを読み込めなかったときの対応もできてると。
ちなみにminmaxのアルゴリズムだが、
要素を1つ取り出して、これを暫定最大・暫定最小にする。
そして要素を2つ取り出して、このうち大きい方を暫定最大と比較して必要に応じて入れ替えて、
小さい方を暫定最小と比較して必要に応じて入れ替えて、というのを要素がなくなるまで繰り返し。
これで要素2つあたり3回の比較で済むという寸法。
こんなのList::MoreUtilsにあるからそれでいいじゃないのというのはもっともな話だが、
知っておくとお得なこともあるかも。
Author : hidemaro
Date : 2009/03/25(Wed) 22:56
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

irbをパクってiplを完成させてみた

やっと冊子が完成した。
やっと春休みがやってきた、というのが部員の感想ですね。
僕の記事はただでさえページ数が多いのに、それで字がすごく多いから、インクの消耗量がすごいはず。
いろいろ大変でしたが、最終的にはうまくいってよかった。
そういえばperlshっていうものは世の中にあるんですね。
Term::ReadLine::Gnuのおまけとしてついてるんですね。
Tabで候補が出てくる以外はそう素晴らしい機能があるわけではない。
というかData::Dumper使ってないあたりからして残念すぎる。それにWindowsで使えない。
それと自分の作ったやつ(「perlshで気軽にできる自動化」参照)の名前がかぶってるなぁと。
それならと自作の方をiplに名前を変えてみた。irbのパクリですね。
それにあわせていろいろ変えてみた。
複数行の入力がしたいときというのはやはりあるのだが、
そのために2つの方法を用意した。
1つは1行目の行末が{で終われば、そこから継続して入れられて、空行が来たらそこで終わりと。
> for(1..10){
* print "$_,";
* }
*
1,2,3,4,5,6,7,8,9,10,=> ''
もう1つ空行があっても大丈夫な方法を考えてみた。
> ##foo
* $x=q{
* 111
* 222
*
* 333
* }
* ##foo
##xxxからはじめて##xxxで終わると。これならいくらでも打てますね。
あと、以前から取り付けていたファイルを読み込むfr、ファイルに書き込むfw、追記するfa、
ファイル一覧を取り出すlsと、データをわかりやすく表示するpを用意しておいた。
ipl.batをBZip2で圧縮したものをActivePerlのbinに入れれば動きますよと。
結構使い勝手はいいと思う。
前から使ってるけど電卓代わりに役に立つ。
まぁカンマで桁区切りできないけどね。Perlの桁区切りは_です。1_000_000のように書けるんですよ。
それさえ気にすれば電卓に使うには便利。
Author : hidemaro
Date : 2009/03/23(Mon) 23:04
Perl・PHP・Ruby・Python | comments (0) | trackback (0)

Tools