その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

B::perlstringを使って文字列中のダブルクォートを適切にエスケープする

文字列中にエスケープされていないダブルクォートがあった時に,例えば文字列evalしようとするとずっこける事があります.以下の様な感じ.

なぜ失敗するかというと,eval "$str"eval "hel"lo"という風に評価されてしまうからなんですね.これではlo"がinvalidになってしまいます.


で,そういう時にどうするかと言うとB::perlstrigですよ!

こうすると動く.
B::perlstring('hel"lo')という風にしてやると,'hel\"lo'という風に適切にダブルクォートをエスケープしてくれる訳ですね.


こういう場合「男は黙って正規表現」と思っていましたが,B::perlstringで良い気がしました!


[追記]
文字列evalはあくまで***例***なんで真に受けないで欲しいんですけど,他に良い例が思いつかなかったと言うか,実際のソースとか使い道とか書いてもいいんですけどそれだと異常に長くなるし,だったら面倒だから「単純な」文字列evalで良いやってなって例示しただけなので,まあ色々あります.これが全てでは無い.まれにq{...}とかやっても無駄な場合もある.そういう時に必要になることがある.
詳しくはLocalizerのソース,特にGettext周りを読めば良いと思いますね!

Yokohama.pm #10に参加してきました

Yokohama.pm #10に参加して参りました.
Yokohama.pmヤバくて,無限にビールは飲めるわ有限に食事はできるわ,加えて学びを得られるわで最高のイベントと言っても過言ではない感じでした.KAYAC社はすごい.


さて,詳細なレポートなどは他の参加者の方が素晴らしい感じでまとめてくださっているでしょうから,そちらを見て頂ければ良いとして,ここには僕のやったLTの資料などを貼ります.電話の市外局番の話です.日本でこの情報欲してるの数人しかいないと思う!


3行でまとめると,

  • Number::Phone::JP::AreaCodeという市外局番扱うモジュールを書いた
  • 総務省イカれた愉快なデータをパーズするの大変
  • そこそこ動いているけど,データの抜けとかありそうだから見つけたら教えて欲しい

という感じです.
総務省の配布するデータのパーズ,めっちゃ大変なので誰か一緒にやりましょう.

ちなみにリポジトリはこちらです.CPANに上げるかどうかはわかりません.
https://github.com/moznion/Number-Phone-JP-AreaCode
(author以下が本当に地獄です)


何かあったら教えてくださると本当に助かります.よろしくお願いします!

Localizerが出た

http://blog.64p.org/entry/2014/02/17/192612

Localizerと言うのはYet Another Framework for Localizationのことで,国際化対応のための新しいフレームワークです.インタフェースが従来のものよりイカしていて良いと思います.
Gettextコンパイラの実装を通じて (と言ってもほとんどコピペですが) Gettextについて知見を深められたので良かったと思います.

詳しくはtokuhiromさんのブログを読むと良いと思います.
そして利用されると良いと思います.


それはそうとこの記事,良いと思いますしか言ってないですね.

Digest::MD5のもろもろに関して

第一部

まず,id:amagitakayosiさんのブログ記事に関しまして.
http://amagitakayosi.hatenablog.com/entry/2014/01/31/174915

これの結果がおかしいのは,普通に関数で呼び出すべき所をクラスメソッドみたいな感じで呼んでいる為です.これではclassがdigestの計算文字列として渡ってしまう.従って,下記のように修正すればちゃんと動きます.

この件については以上!!

第二部

Digest::MD5が提供しているOOPはそこまでメリット無いから使わなくても良いのじゃ,という話です.

例えば以下のように書いてみましょう.

hexdigest()メソッド等の,digest算出メソッドでdigestを計算すると,add($str)メソッドで指定した対象文字列がクリアされてしまいます.つまり,この例だと1回目のhexdigest()ではadd($str)で指定したfoobarを元にdigestを計算していますが,2回目のhexdigest()では文字列がクリアされてしまうので空文字列を元にdigestを計算してしまいます *1

従って,所望の機能を実現するためには以下のように書く必要があります.

digest計算のたびにadd($str)で計算対象文字列を指定してやらなきゃ駄目な訳ですね!
これだったらOOP使わずに普通に関数で呼んだほうが楽そうなイキフンが……


と思ったら牧さんが似たようなことを書かれてました.
http://lestrrat.ldblog.jp/archives/23704683.html


しかし,digest計算がオブジェクトの状態に対して破壊的な変更を行うというのは直感的ではない気がしますし *2OOPインタフェースにもそれほど便利なメソッドが生えているわけではないし,オブジェクトの状態はダイジェスト計算の度に吹き飛ぶし,だったらこれオブジェクトにしなくても良いし,それくらいなら関数でええやん,という様々な理由からDigest::MD5OOPインタフェースは使わず,関数を使った方が良いのではないか,という結論に達しました.ダイジェスト計算の度に文字列情報が揮発するのであれば,その文字列は引数として与えたほうが自然な気もしています.


ここらへん,空文字列でdigestを計算しようとしたら例外を投げてくれる,あるいは例外とはいかないまでも警告を出してくれるとかだったらハマる人減りそうで良いと思ったんですが,それやると後方互換がぶっ壊れるから大変そうですね……


[追記]
PerlのDigest::*名前空間のモジュールのOOPインターフェースはある程度統一されているので,様々なダイジェストを取り扱うメソッドなんかがあった時にそのメソッドにDigest::HogeHogeのインスタンスを渡してやれば,ポリモルフィズムを使ってワイワイできるので便利っちゃ便利.

[追記2]
勝手に自分の中でケリが付きました.

  • 基本的には関数を使う
  • OOPインタフェースは変なハマり方をする恐れがあるのでなるたけ使わない
  • ポリモルフィズムを使って他のDigestモジュールとワイワイやりたい時にのみOOPインタフェースを使う
  • もしもそういう実装になった時は一回外を走って頭冷やしてから考え直す

[追記3]
ケリは付いていなかった.コメント参照のこと.

*1:ここはドキュメント (https://metacpan.org/pod/Digest::MD5) にしっかり書かれていますね -> “Once it has been performed, the Digest::MD5 object is automatically reset and can be used to calculate another digest value. ”

*2:少なくとも僕には

正規表現で,他の条件にマッチしない文字列を取得したい

メモ書き程度です.


例えば,

aaafoobbbbarcccfooddd

みたいな文字列があった時に,fooとbarにマッチしない文字列が欲しい時には以下のように書くと良い.

$str =~ m/(.*?)(?:foo|bar)/g;

実行すると以下のような値が得られる.

$VAR1 = 'aaa';
$VAR2 = 'bbb';
$VAR3 = 'ccc';


加えて条件のキャプチャをするようにすれば,つまり

$str =~ m/(.*?)(foo|bar)/g;

と書いてやれば,

$VAR1 = 'aaa';
$VAR2 = 'foo';
$VAR3 = 'bbb';
$VAR4 = 'bar';
$VAR5 = 'ccc';
$VAR6 = 'foo';

という結果が得られるので,簡単なパーザであれば楽に書ける風味.

im.kayacでカジュアルにメッセージ送るPerlのライブラリ作った

im.kayacを使ってカジュアルにメッセージを送るPerlのライブラリ,WebService::ImKayac::Simpleを作成・公開しました.

https://github.com/moznion/WebService-ImKayac-Simple
https://metacpan.org/release/WebService-ImKayac-Simple


im.kayacでメッセージを送るためのPerlライブラリとしては,GitHubで公開されているWebService::ImKayacや,@さんのAnyEvent::WebService::ImKayacが既に存在していて,これマジで良いんですけれども,両者とも内部でAnyEventを使用していて,別にAnyEventを使わなくてもよくね? というシーンではオーバーキル感がありました.

で,そういう場合は普通にPostリクエストを送信してim.kayacでメッセージを送る,という処理を都度都度心をこめて手で書いていた訳ですが,そろそろ再利用可能な部品にしても良いのではないか*1,という気持ちが不意にグワァーッと湧いたのでガリガリッと書いてガッチャーンとリリースした形になりました.


以下のように書くとメッセージを送信する事ができます *2

use WebService::ImKayac::Simple;

my $im = WebService::ImKayac::Simple->new(
    type     => 'password',
    user     => '__USER_NAME__',
    password => '__PASSWORD__',
);

$im->send('Hello!');

AnyEvent::WebService::ImKayacコンストラクタWebService::ImKayac::Simpleコンストラクタはインターフェースを合わせているので,WebService::ImKayac::SimpleからAnyEvent::WebService::ImKayacに変更したいワだとか,あるいはその逆の場合などでも容易に移行が可能となっています.


ご利用下さい.

*1:いちいちSHA-1のハッシュを作ったりするのも面倒なので

*2:この例ではパスワード認証でメッセージを送っています

NHK番組表APIを触る為のPerlクライアント作った

去る2014年1月27日にNHK番組表APIが公開され,これが中々良い感じだったので,PerlからそのAPIを触れるクライアントであるWWW::NHKProgram::APIを書きました.

https://metacpan.org/release/WWW-NHKProgram-API
https://github.com/moznion/WWW-NHKProgram-API


このモジュールを使うと,NHK番組表APIが提供している

  • 地域,サービス (いわゆるチャンネル),日付の指定による該当する条件の番組リストの取得
  • 地域,番組のジャンル,日付の指定による該当する条件の番組リストの取得
  • 番組IDの指定による該当する番組情報の取得
  • 地域,サービスの指定による,現在放送中の番組情報の取得

の機能を利用することが可能となります.APIの詳細に関しては以下を参照してください.
http://api-portal.nhk.or.jp/ja
http://api-portal.nhk.or.jp/doc-request


例えば以下のように書くと2014年1月1日のNHK総合1 *1 の東京リージョンの番組表を取得出来ます.

use strict;
use warnings;
use WWW::NHKProgram::API;

my $client = WWW::NHKProgram::API->new(
    api_key => '__YOUR_API_KEY_',
);

my $program_list = $client->list({
    area    => 130,
    service => 'g1',
    date    => '2014-01-01',
});

あるいはuse utf8;していれば (2014-02-05 23:44 追記: use utf8いちいち強制するのめんどいから無くても大丈夫にしました) もう少し人間にわかりやすく書くことも可能です;

use strict;
use warnings;
use WWW::NHKProgram::API;

my $client = WWW::NHKProgram::API->new(
    api_key => '__YOUR_API_KEY_',
);

my $program_list = $client->list({
    area    => '東京',
    service => 'NHK総合1',
    date    => '2014-01-01',
});

(と書いたもののAPIの仕様上,取得可能な情報は当日の情報及び翌日の情報のみのようです.それ以外の日付を指定してリクエストを投げると400が返ってきます)


で,以下のように書くと,観たい番組の放送時間が近づくと教えてくれるtwitter botもどきが作れたりします.

use strict;
use warnings;
use utf8;
use Net::Twitter::Lite::WithAPIv1_1;
use WWW::NHKProgram::API;

my $nt = Net::Twitter::Lite::WithAPIv1_1->new(
   consumer_key        => $consumer_key,
   consumer_secret     => $consumer_secret,
   access_token        => $token,
   access_token_secret => $token_secret,
   ssl => 1,
);

my $client = WWW::NHKProgram::API->new(
    api_key => '__YOUR_NHK_PROGRAM_API_KEY__',
);

my $program_now = $client->now_on_air({
    area    => '東京',
    service => 'NHK総合1',
});

my $wanna_watch = "妄想ニホン料理";
if ($program_now->{present}->{title} =~ /$wanna_watch/) {
    $nt->update($wanna_watch . 'はじまったよ!');
}
elsif ($program_now->{following}->{title} =~ /$wanna_watch/) {
    $nt->update($wanna_watch . 'そろそろやるっぽい!');
}

これで妄想ニホン料理を見逃す心配が無くなる!!!!


NHKの番組表API本当に良くて,設計はシンプルだし必要な番組の情報もほとんど取れるし,その上テレビだけではなくラジオ番組の情報まで取れるしで非常に便利です.
番組表情報と番組情報取得のAPIの上限数が少ない (300requests/1day) かなーとか思ったけれど,1日分の番組表のデータをバカスカ取る機会は少ないだろうし,「現在放送している番組の情報」を取得するためのAPIは上限1500requests/1dayとかなり余裕があったので全然問題無い感じでした.

いやー,ぶっちゃけXMLとかじゃなくてJSONで返ってくるのが本当に嬉しい! あと取得に失敗してるのに200を返してくるとかそういう意味不明な仕様じゃないだけでもう嬉しい!!!! 最高だ!!!!!


ぜひご活用下さい.

*1:どうやらNHKの放送の名称は全角英数字が正式な様子.なのでこのモジュールでもそれに則っています