カテゴリ: perl

2日目の感想書いていきます。

2日目は10時半スタートで、休日のエンジニアにはなかなかつらい時間です。

しかし、1限からみたいトークだらけでだったので朝から参加。

「新しい」を生み出すためのWebアプリ開発とその周辺 -Yusuke Wada

yusukebeさんのトーク。今年のベストスピーカー1位のトークです。なにがビックリしたって、朝一のトークなのに会場は凄い人数でした。

内容としては、新しいサービスを作るときに、どのようなステップでサービスを作り上げていくか、yusukebeさんの体験を基に話されていました。一番はじめに「哲学」がありきってのは凄く良いアプローチだなと思いました。

朝一にもかかわらず、おっぱいの話やYourAVHostの話がでくるあたりが、らしいなという感じです。また、ボケてのスライドはスベリしらずでちょっとズルいなとw

なお、yusukebeさんのイチオシ女優は成瀬心美だそうです。これ大事。

 

次の時間帯のトークも聞きたいの一杯あったんですが、LT-Thonの方がきになってしまい、しばらくLT-Thonを聞いていました。もともと予定されていたLT意外にも、どんどん希望者がでてきて、異様な盛り上がりを見せていました。LTの雰囲気も凄くよかったし、普通にレギュラーのトークとしても面白いものが沢山あって、離れられなくなってしまいました。

ランチを挟んで午後の部です

Perl今昔物語 -Tomihisa Fuon

こちらはパネルディスカッション形式で、いままでのYAPCの歴史を振り返るという企画

パネラーはmiyagawaさんnekokakさんtokuhiromさんnaoyaさん凄い顔ぶれです。自分はYAPCの初参加は2008年だったので、それ以前の話を聞くのは新鮮でした。このトークの中で何度かでていたのが、Perlだけでなく、他の言語を使うとこでいろいろな物が見えてくるって話。確かにそうだなぁと思う反面、最近Perlしか書いてないので、たまには別の言語で書いてみようかなと思わせてくれる内容でした。

ちょっとショックだったのは、emacs派かvim派かって話がでたときに、「emacs使いはおじさんだからね」って話があったときでしたw

トーク後の質問で「最近新しい技術とかモジュールの流れが止まってませんか?」というなかなか鋭い質問があがってました。確かに今年はどちらかというと運用に関わる話が多かったと思います。この質問に対して、miyagawaさんが「新しいモジュールとかが出来る流れって、YAPCのトークのためのネタ作りから生まれる」みたいな事を言っていて、Perlハッカーって凄いなと改めて感じました。その辺りの話凄く面白いので見てない方は動画で見てみると良いと思います。


そういえば、この時間の裏でやっていたLT-THONがめちゃくちゃ盛り上がってたけど、なにがあったんだろう・・・いまだに気になっています。


10 more things to be rapped off -Tatsuhiko Miyagawa

ことしのベストスピーカー賞2位のトークです。

一つ前のパネルトークでmiyagawaさんやnaoyaさんが言っていた、他の言語をつかっていると見えてくる物があるとか、これからまた技術の入れ替わりがあるかもよ?という話の一つの回答のようなトーク。他の言語ではこんな便利な物あって、こういうのPerlでもあるといいなぁというモノを紹介されてました。20分のトークだったので、全部紹介しきれなかったのですが、あとでスライド見るのが楽しみです。そのうちいくつかはすでにPerlでの実装が進んでいるようなので、今後も注目ですね。

ここで再びLT-THONが気になってきたので、見に行くことに。ここからLTまではずっとLT-THONの方をみていました。ほんとトークも聞きたかったんだけど、結局どれか一つしかみれないし、LT-THONのいつ何が発表されるか解らない感があって、離れられませんでした。トークの方は動画でもみれるけど、LT-THONの方はどうなるのかちょっと解らなかったからというのもあります。

IMG_6121

画像だとこんな感じ。ちょうどYappoさんが飛び込みの超LTでドラクエの話をされてるシーンです。ほんとにドラクエの話を淡々としてて面白かった。

席に結構空きがあるように見えますが

IMG_6122

実は立ち見が一杯います。この後ろにも充電しながら見てる人たちもズラッと居ます。教室だと座りっぱなしなので、立っていたくなるんですね。このLT-THONの何が起こるか解らない感じがめちゃくちゃ面白かった。あとすっごいマニアックなトークも多くて、エクセルネタや電子工作などバラエティに富んでいて飽きませんでした。

ほんと良い企画だったと思います。もっと沢山の人がしゃべれそうな感じだったので、来年は複数あっても楽しいかも。まぁ見る側は何処見て良いかわからずもどかしくなりそうですけど・・・

Lightning Talk

LT2日目。相変わらずレベル高い&腹痛い。ほんとどれも面白かったんですが、印象強かったのが「Imager::Heatmapでホットなエリアを可視化する!」と「それ PHP でできるよ」と「Perl11」と「みんなだいすきサスペンダー」あたりです。とくにIngyのPerl11はインパクト強かった。

How Perl Changed My Life -Gosuke Miyashita

ことしの最後のトークはmizzyさんによるお話。ここ最近の慣例で、最後のトークは技術的な話ではなく、ちょっと心に来るお話。

Perlを始めて、モジュールかいて、トークをすることで、どんどん人生が変わっていったんだよって話は、あの場にいた人たちに自分達ももっといろんな事に挑戦してみよう!と思わせてくれたんでは無いでしょうか。

トークの終わり頃に、Perlの産みの親であるLarry Wall氏にmizzyさんが「Perlに出会って人生かわりました、ありがとう」(もちろん英語で)語りかけていて、こうやって直接お礼を言えるのって凄いなって思います。なかなか無いですよねこういう機会。Perlはそういう機会が普通にあるのが凄い。

そういえばmizzyさんが「みなさんにとっての人生をかえた事を感想を書くときにでも教えてください」って言葉があったので、自分にとって人生が変わったなと思える事を挙げてみます。

私の人生を変えたのは、私が前職でSIerをやっていたときに出会った先輩です。技術を純粋に楽しんでいる方で、色々はWebサービスや本を紹介してくれたり、習慣やLifeHackを教えてくれたりしました。当時、SIerでのコンサル的な仕事は楽しかったんですが、その先輩に会ったことでWebって面白いな、インターネットって凄いなって思うようになったのでした。

mizzyさんのトークを聞いて、あの頃の気持ちに戻って、また色々やってみようかなという気持ちになりました。とっても良いトークでした。

Closing -Daisuke Maki

なんだかあっという間にクロージングです。ベストトークの発表があったり、今年の統計やなんかの発表がありました。今年の参加者はなんと841人!ここでtwitter上であと100人で941だったのに!ってみんなツイートしてて面白かった。自分もしたんですけどねw

最後の方で、来年はTokyo以外で実施しても良いんじゃない?みたいな言葉があって、来年がどうなるのかドキドキです。まぁそうなると個人的にはどうしようかな・・って所ではあるんですが・・・

2日間あったYAPCもあっという間に終わってしまいました。毎年おもうけど、YAPCにくるとモチベーションが上がって、アレやってみようかな、コレやってみたいなというモノが沢山あって、エネルギーを貰える感じがします。また来年参加出来ることを楽しみにしています。

それまでこのモチベーションを維持していきたいなぁ・・

最後に、運営の皆様、ボランティアスタッフの皆様、スピーカーの皆様、そして参加されたすべの皆様、ほんと楽しいイベントでした。お疲れ様でした!

このエントリーをはてなブックマークに追加

ことしもYAPC Asia行ってきました。
イベントの様子や見てきたトークについて書いてみたいと思います。

IMG_6101
今年は3年ぶりに会場が変わって、東大の本郷キャンパスで開催されました。

IMG_6110
会場は東大赤門のすぐ近く。折角なので写真を一枚。
開催される週の頭には、台風直撃でどうなるやら・・と心配してたのですが、なんと台風が直前でそれるという奇跡が起こり、ちょこっと雨は降ったぐらいですみました。ひとえに天候を操る力をえた941さんのおかげでしょうか?

IMG_6102
会場となる建物はこちら。最近出来てばかりの棟でめちゃ綺麗&格好良かったです。

IMG_6103
1日目のスタート直前。受付は長蛇の列でした。

IMG_6104
こちら941さんによるオープニングトーク。朝10時スタートにもかかわらずこの人出。今年はさらに参加者が増えたてますます大きなイベントになった感があります。

What Dose Your Code Smell Like?  - Larry Wall

オープニングトークの後はPerlの産みの親である、Larry Wall氏によるKeynote。2010年にもYAPCでトークを聞いたんですが、2年後にまた普段使っている言語の開発者のトークが聞けるって、凄いイベントですよね。

2010年は、Perlと他の言語の対比をしながらのお話で、タイトルから今年もそんな内容なのかな?と思ったんですが、実はPerl6のお話でした。普段使っているPerl5とPerl6はかなり言語仕様に違いがあって、まるで別の言語のようなのですが、なぜそのような違いがあるのか、Perl5で書かれたコードをPerl6に直しながら、思想を話していました。

その話を聞くと、たんに利便性を求めて変更している訳ではなく、ここはこうあるべきだから変更されているんだというのが非常に良くわかりました。

仕事で使うPerlは5を使い続けることになりますが、プライベートでPerl6を使ってみるのもいいな、と思いました。


Larry氏のkeynoteを聞いたあと、別の会場に来てみたんですが、こちらまた凄いカッコイイ部屋でビックリしました。

IMG_6108

屋根裏部屋のような特別教室です。

IMG_6109

なんと椅子がすべてバロンチェア!でした

pixivのサムネイル事情 -bokko

そのオシャレ教室で聞いたトーク。bokkoさんによるpixivでの画像取り扱いの話。

ちょっと前に、Cureというコスプレ画像共有サイトを担当していた時期があって、当時は画像周りをあれこれいじっていたので、なんか話を聞いていてうんうん頷いてしまいました。

面白いなと思ったのが、アップロードされた画像を処理する際に、サムネイルを作成し終わるのを待たずに、詳細情報を入力するページに遷移させて、ユーザーが情報を入力している時間に裏でサムネイルをごりごり作っているという事。サイトの特性を上手く利用されているなぁと思いました。

あと動的画像変換proxyであるmod_small_lightを改造して使っていて、漫画なんかの複数のページを一枚の画像にしているながーい画像のサムネを生成するときに、一番上の方を切り抜いているってのを聞いて、たまーにCureでもそんな画像あったので、これ真似するといいかもなぁとか思っていました。

Perlでデータクリーニング -Toshinori Sato

overlastさんによる自然言語処理の話。

Webサイトを開発・運営している時に、なんだかんだで必要となってくる自然言語処理のチュートリアル的なお話でした。どんなツールをどうつかって・・・とかではなく、どんなデータに対して、どのような観点でクレンジングすると良いかという話で、多分自然言語処理に詳しくない人にとっては意外と思う話もあると思います。

そういえば2010年にもPerlで自然言語処理ってタイトルでトークされていて、私もそれを会場で聞いていました。ググっていたら自分のブログも出てきました。実は同じ職場で一緒に仕事させて頂いて、何時も新鮮な刺激を与えてくる人でもあります。すいません何時もたよってばっかりで。自分でも自然言語処理に挑戦したいなと思う今日この頃です。

いつも思うんですけど、スライドやトークの仕方が素晴らしく上手いので、そういった面でも勉強になります。



ここで午前の部はおしまい。今年は941さんの発案による、お一人様でも安心!な企画があって、ランチに行く人をくじ引きで4人集めて行くというもの。しかもランチ代1000円が支給されるという企画です。確かに一人で参加しているとぼっちメシになってしまうので、凄く良い企画だと思いました。
 

自分は、なんとここで担当案件でトラブルがあって、ネットが繋がるところを探して一人で歩き回っていました。結局本郷三丁目のマックでなんとか対応して戻って来ましたが、午後のトークは始まってしまっていました。
 

で、折角なのでここで今回新たに企画されたLT-THONの様子を見にいってみました。

LT-THONはひたすら2日間LTを続けるというもので、事前エントリ制ではありましたが、飛び入り参加あったりで予想以上に楽しい企画でした。これは2日目のレポートにまた書こうと思います。



位置情報系処理のお話 a.k.a. 続・自文書抽出日本的住所 - Kazuhiro Osawa

Yappoによる位置情報に関するお話。位置情報を扱う上でのPerlモジュールの話(GeoHash系が多かった)とか、実際に住所の標準化処理をする際に問題になるめんどくさい北陸あたりや熊本辺りの話が興味深かったです。

あと白地図APIの話もあって、位置情報系のサービスでなくとも使う機会ありそうでおもしろいなーと思いました。

平均レスポンスタイム50msをPerlで捌く中規模サービスの実装/運用 -Tatsuro Hisamori

今年のベストトーク第3位。最近はやりのネコ写真をふんだんに盛り込んだスライド

Web広告の話なんですが、Web広告の歴史から始まり、近年話題になっているDSP(Demand Side Platform)の話をFreak out!さんでの実例を交え話されていました。

サイトが表示されてから広告が表示される(べき)タイミングというのは本当に刹那の瞬間であって、その短い50msという間に色々処理するためにはどうしたらいいのか?という話で、実はどのサービスでも当てはまるような、大事なお話でした。

結構当たり前の事をしっかりやっていくのが大事ということを痛感させられました。

Perlアプリケーションのベンチマークとプロファイリング -Shunichiro Fujiwara

fujiwaraさんによる、アプリケーションのチューニングの話。個人的にはベストトークに推したいぐらい、網羅的で良くまとまっていて、参考になるお話。

アプリケーションの何処がボトルネックになりやすいのか?いかにして計測するか?というのがいろいろな方法や判断の仕方を話されていて、fluentdやらDevel::NYTProfだとか今年のトークと重なる話があって、とくに裏番組のtagomorisさんと関わるような話がいくつかあって、ちょっと面白かったです。偶然なのか、プログラム決めた牧さんマジックなのか・・

チューニングの模範的なトークでした。ISUCON優勝者は伊達ではありませんね。

Lightning Talks Day 1

1日目最後のプログラムです。どれもコレもハイレベルなLTで、ホント笑いっぱなしでした。

特に印象強かったのをいくつかあげてみると、「おどけでね Sendai.pm」と「Perlでおねえさんを救った話」と「Perlと人生」という話がかなり笑わせていただきました。すごいなーと思うのはスポンサートークもLTとしてすっごく面白かったこと。LTって難しいのに凄いなと思います。あとドラ娘可愛かった。

 IMG_6111

この後は懇親会。今年も凄い人数で圧巻でした。パノラマで一部とってみました。

料理は椿山荘のケータリングだったらしくめちゃくちゃ旨かったけど、殆ど食べれなかった。人が多すぎだったw


ほんとは一つのエントリでまとめようと思ったんですが、書いてたらかなり長くなったので、Day1とDay2分けて書こうと思います。1日目も楽しかった!

このエントリーをはてなブックマークに追加

IPhoneやらAndroidで取った写真のExifをみて画像を回転させるのをたまーに実装するんですが、滅多にすることなくて、やる度に仕様調べないと思い出せないので、ブログに書いておこうと思います。

画像をどう回転させれば良いかは写真についてくるAPP1セグメントに定義されているTIFFフォーマットの0thIFDにあるOrientationタグみると解ります。

*5と7が逆だったのをブコメで指摘頂いて訂正しました。下記のpdfドキュメントに誤りがあったので修正版に差し替えています(2013/9/2)

まぁちゃんと理解はしてないんですけど、仕様はCIPAにあるhttp://www.cipa.jp/hyoujunka/kikaku/pdf/DC-008-2010_J.pdfhttp://www.cipa.jp/hyoujunka/kikaku/pdf/DC-008-2012_J.pdfに定義されています。これみてもいまいち解らないので、図解してあるこっちが解り易かったです。

GPS情報もExifから取れるので、必要な方は仕様をみてみると良いと思いますが、すでにライブラリ沢山あると思うので読まなくても大丈夫だと思います。

で、このOrientationタグの中身が数値で、どれがどれだかすぐに忘れます。

Orientation=1: そのまま
Orientation=2: 水平反転
Orientation=3: 180度回転
Orientation=4: 180度回転て水平反転
Orientation=5: 時計回りに90度回転して水平反転
Orientation=6: 時計回りに90度回転
Orientation=7: 時計回りに270度回転して水平反転
Orientation=8: 時計回りに270度回転

図にしたのが上にはったpdfにかいてあったので抜粋(2013/9/2差し替え)

43

これをimage magicのconvertコマンドでやると、こんな感じになります。

Orientation=1: そのまま
Orientation=2: convert -flop original.jpg flop.jpg
Orientation=3: convert -rotate 180 original.jpg rotate180.jpg
Orientation=4: convert -rotate 180 -flop original.jpg rotate180-flop.jpg または convert -flip original.jpg flip.jpg
Orientation=5: convert -rotate 90 -flop original.jpg rotate90-flop.jpg または convert -transpose original.jpg transpose.jpg
Orientation=6: convert -rotate 90 original.jpg rotate90.jpg
Orientation=7: convert -rotate 270 -flop original.jpg rotate270-flop.jpg または convert -transverse original.jpg transverse.jpg
Orientation=8: convert -rotate 270 original.jpg rotate270.jpg

transposeとtransverseはちょっと解り辛いですね。最初5と7を取り違えちゃいました。

実際に画像でやってみたほうが解りやすそうなので、先日コンプしたLINEシールの画像つかって試して見ました(これ使うと四隅が解りやすい)

1 6 3 8
original
rotate90
rotate180
rotate270
2 5 4 7
flop
rotate90-flop
rotate180-flop
rotate270-flop
となります。とはいっても、下段の水平反転系はほとんど見たことありません。水平反転ってどうとったらなるんでしょうね?

最後にPerlでの実装例の一部を乗っけておきます。

こっちは、ImageMagicで変換するパターン

if (substr($org_data, 0, 2) eq "\xFF\xD8") {   # if jpeg
    my $img_meta = Image::MetaData::JPEG->new(\$org_data);
    my $exif_image_data = $img_meta->get_Exif_data('IMAGE_DATA', 'TEXTUAL');
    $jpeg_orient = ($exif_image_data ? $exif_image_data->{Orientation}->[0] : 1);
    if ($jpeg_orient == 2) {
        $img->Flop();
    } elsif ($jpeg_orient == 3) {
        $img->Rotate(180);
    } elsif ($jpeg_orient == 4) {
        $img->Flip();
    } elsif ($jpeg_orient == 5) {
        $img->Transpose();
    } elsif ($jpeg_orient == 6) {
        $img->Rotate(90);
    } elsif ($jpeg_orient == 7) {
        $img->Transverse();
    } elsif ($jpeg_orient == 8) {
        $img->Rotate(270);
    }
}

もう一つImagerを使ったケース。やっている事は変わりません

if (substr($image, 0, 2) eq "\xFF\xD8") { # if jpeg
    my $img_meta = new Image::MetaData::JPEG( \$image ) or return $im;
    my $im = Imager->new;
    $im->read(data => $image) or return undef;
    my $exif_data = $img_meta->get_Exif_data('IMAGE_DATA', 'TEXTUAL');
    my $jpeg_orient = ($exif_data ? $exif_data->{Orientation}->[0] : 1);
    if ( $jpeg_orient == 2 ) {
        $im->flip(dir=>"h");
    } elsif ( $jpeg_orient == 3 ) {
        $im = $im->rotate(right=>180);
    } elsif ( $jpeg_orient == 4 ) {
        $im->flip(dir=>"v");
    } elsif ( $jpeg_orient == 5 ) {
        $im = $im->rotate(right=>90);
        $im->flip(dir=>"v");
    } elsif ( $jpeg_orient == 6 ) {
        $im = $im->rotate(right=>90);
    } elsif ( $jpeg_orient == 7 ) {
        $im = $im->rotate(right=>270);
        $im->flip(dir=>"v");
    } elsif ( $jpeg_orient == 8 ) {
        $im = $im->rotate(right=>270);
    }
} 
このエントリーをはてなブックマークに追加

今担当しているサイトでは、いろんなニュース提供元から送られてくる、様々なXMLをParseしていて、内容も様々なので、色々なエラーが出ていました。

チーム内でも軽微なエラーならスルーされていたところだったので、 ここ半月ぐらい、cronで飛んでくるエラーをながめ、一つ一つ調査、対応してきました。

その過程で感じた事とかやったことをまとめておこうかと思います。

まず思ったことは、

人類はXMLを全然使いこなせてない

ってことです。大げさに聞こえるかもしれませんが、そもそもXML文書として不正なものや、 昨日まで問題無かったのに、突如エラーになるfeed、予告無しにプチリニューアルするフォーマット、 当然の如く入り混んでくる制御文字など、色々なパターンでエラーになります。 

ということで、外部のXMLをParseする際に気をつけた方が良いと思う事をまとめます。

フォーマットが指定できるなら出来るだけ指定する

既にあるAPIやfeedを読むだけだとこれは難しいですが、新規のシステム連携などの場合は、 コチラが欲しいXMLは出来るだけフォーマットを用意しておいた方が良いです。

色々なパターンに対応しなくてすむし、対応するにしてもかなり場所を局所化できます。 カッチリフォーマット決めても守ってくれない or 間違う事も結構あります。

ちょっとした事でもコチラで対応するのではなく提供側に直して貰いましょう。ルールは厳格に運用しないと意味が無くなります。

当たり前だと思われるかもしれませんけど、これ実際にカッチリやるのかなり難しいんですよね・・・

CDATAセクションを確認

嘘のような話しですが、コンテンツ部分に生のhtmlがそのまま入ってくる事があったりします。CDATAセクションにして上げればいんですが、 そのままスルーするとhtmlがXMLのコンテンツとして解析されて変な事になります。かならずCDATAセクションに修正して貰いましょう。

リトライ処理を必ずいれる

ネットワーク越しだと、アクセスすれば必ずデータが帰ってくるということは保証されません。 URIにアクセスするような処理は、かならずリトライを入れましょう。

それでも失敗するケースもあるので、その場合はエラー出力しておきましょう。

数値参照や実体参照でない"&"は変換

"&"は特殊な文字扱いで、&などの実体参照形式に変換しないといけません。が、本来の"&"の用途でそのまま変換されずに入ってくることがよくあります。 そのままParseするとエラーになっちゃうことが多いと思うので、しっかり& -> &にしてあげましょう。

その際、元々あった実体参照をくずさないように、ちょっとだけ工夫してあげる必要があります。以下perlの例です

$contents =~ s/&(?![#0-9a-zA-Z]+;)/&/g;

制御コードを一部以外削除する

その制御コードどうやって入力した!?ってコードが入ってくる事があります。asciiで指定されている制御コードは0x01~0x1fと0x7fがあります。 このうち0x09は水平タブ、0x0aは改行(LF)なので残してあげないと文書がおかしくなります。windows環境なら0x0d(CR)も残してあげても良いです。

Perlでparseするとその他の制御コードは

not well-formed (invalid token) at line 4, column 25, byte 99 at /usr/local/lib64/perl5/site_perl/5.8.8/x86_64-linux/XML/Parser.pm line 187

なんて感じで怒られたりします。

$contents =~ s/[\x01-\x08\x0b-\x1f\x7f]//g; # delete control code

エラーは捨てない

cron等でparseする際、ついついエラーを" > /dev/null 2>&1"しちゃったりするかもしれませんが、予期せぬエラーが絡むので、これは勿体ないです。かならずエラーを通知するようにしましょう。

すぐに見れなくても、いつか見るor誰かがきっと見て参考にします。

PerlでXMLをparseする際のパーサー選択

XML::Simpleを使っていたりするとParser部分を指定することができます。

大分昔にid:naoyaさんがXML::Simple におけるパーサーの実行速度比較ベンチ取っていたのですが、もう7年も経っているので改めてベンチしてみました。コードはリンク先のものを使わせて貰っています。

ついでにXMLのファイルのサイズも2パターンやってみました 

軽量のXML(5.3k)をparseした結果

Benchmark: timing 1000 iterations of XML::LibXML::SAX, XML::Parser, XML::SAX::Expat, XML::SAX::ExpatXS...
XML::LibXML::SAX:  5 wallclock secs ( 4.66 usr +  0.01 sys =  4.67 CPU) @ 214.13/s (n=1000)
XML::Parser:  2 wallclock secs ( 2.24 usr +  0.00 sys =  2.24 CPU) @ 446.43/s (n=1000)
XML::SAX::Expat:  7 wallclock secs ( 7.21 usr +  0.00 sys =  7.21 CPU) @ 138.70/s (n=1000)
XML::SAX::ExpatXS:  3 wallclock secs ( 2.75 usr +  0.00 sys =  2.75 CPU) @ 363.64/s (n=1000)

大きめのXML(1.5M)をparseした結果

Benchmark: timing 100 iterations of XML::LibXML::SAX, XML::Parser, XML::SAX::Expat, XML::SAX::ExpatXS...
XML::LibXML::SAX: 819 wallclock secs (818.18 usr +  0.27 sys = 818.45 CPU) @  0.12/s (n=100)
XML::Parser: 23 wallclock secs (23.86 usr +  0.01 sys = 23.87 CPU) @  4.19/s (n=100)
XML::SAX::Expat: 84 wallclock secs (83.18 usr +  0.00 sys = 83.18 CPU) @  1.20/s (n=100)
XML::SAX::ExpatXS: 31 wallclock secs (31.56 usr +  0.00 sys = 31.56 CPU) @  3.17/s (n=100)

小さいファイルの方でXML::LibXML::SAXはもうちょっと早いかと思ったんですが、XML::Parserの半分の速度でした。 しかも、ファイルサイズが大きくなるとXML::LibXML::SAXはかなり遅くなってしまいます。

XML::LibXML::SAXのエラー表示は詳しくて良いんですが、ここまで差がつくならXML::Parserを使っておくのが無難そうですね。

このエントリーをはてなブックマークに追加

仕事で久々にTime::Pieceを扱っていて、localtimeの取り方がちょっと良くわからなかったので調べてみました。

事の発端はデータの時刻が一部ずれるという問題で、どうもlocaltimeへ変換するところに問題が有りそうです。実際にきているデータ例は以下のような感じ。
%Y-%m-%d %T+09:00
%Y-%m-%dT%T JST
%Y-%m-%dT%T+09:00
%Y-%m-%dT%T+0900
%Y-%m-%dT%T+9:00
%Y-%m-%dT%T-07:00
%Y-%m-%dT%T-08:00
%a %B %d %T %Y +0900
%a %b %d %T JST %Y
%a,%d %b %Y %T +0900
%a, %d %B %Y %T +0900
%a, %d %B %Y %T GMT
%a, %d %b %Y %T +09:00
%a, %d %b %Y %T +0300
※一部割愛
まぁいろんなケースがあります。でこの形式の時間をこんな感じで処理してました。
my $t = eval { Time::Piece->strptime($str, '%Y-%m-%d %T+09:00') } ||
        eval { Time::Piece->strptime($str, '%Y-%m-%dT%T JST') } ||
        eval { Time::Piece->strptime($str, '%Y-%m-%dT%T+09:00') } ||
        eval { Time::Piece->strptime($str, '%Y-%m-%dT%T+0900') } ||
        eval { Time::Piece->strptime($str, '%Y-%m-%dT%T+9:00') } ||
        eval { Time::Piece->strptime($str, '%Y-%m-%dT%TZ') } ||
        eval { Time::Piece->strptime($str, '%a %B %d %T %Y -0800') } ||
        eval { Time::Piece->strptime($str, '%a %b %d %T JST %Y') } ||
        eval { Time::Piece->strptime($str, '%a %d %b %Y %T -0800') } ||
        eval { Time::Piece->strptime($str, '%a,%d %b %Y %T +0900') } ||
        eval { Time::Piece->strptime($str, '%a, %d %B %Y %T +0900') } ||
        eval { Time::Piece->strptime($str, '%a, %d %B %Y %T GMT') } ||
        eval { Time::Piece->strptime($str, '%a, %d %b %Y %T +09:00') } ||
        eval { Time::Piece->strptime($str, '%a, %d %b %Y %T +0300') };
   #一部割愛
$tにはTime Zoneまで考慮された時刻が渡っているという想定です。が、実際は違ってました。

use strict;
use warnings;
use Time::Piece;

sub parse_time {
    my ($time, $format) = @_;
    my $t = Time::Piece->strptime($time, $format);
    warn $t->strftime('%Y-%m-%d %T');
}

parse_time("2012-07-12 18:00:00+09:00", '%Y-%m-%d %T+09:00');
parse_time("2012-07-12 18:00:00+03:00", '%Y-%m-%d %T+03:00');
parse_time("2012-07-12 18:00:00-07:00", '%Y-%m-%d %T-07:00');
 上記コードはタイムゾーン指定が±hh:mmな日付をstrptimeでパースして、グリニッジ標準時の時刻を返します。実際実行してみると・・
2012-07-12 18:00:00 at time-piece-test.pl line 8.
2012-07-12 18:00:00 at time-piece-test.pl line 8.
2012-07-12 18:00:00 at time-piece-test.pl line 8.
ローカルタイムゾーンが全く無視された、GMTとしての2012-07-12 18:00:00が帰ってきます。
ちなみに、こっちだと意図した結果が帰ってきます。
parse_time("2012-07-12 18:00:00+0900", '%Y-%m-%d %T%z');   # print 09:00:00
parse_time("2012-07-12 18:00:00+0300", '%Y-%m-%d %T%z');   # print 15:00:00
日付フォーマットを規定したISO8601では、タイムゾーンの定義はこんな感じ
ISO8601
TZD = time zone designator (Z or +hh:mm or -hh:mm)  
perldocにも書いてありますが、Time::Pieceの時刻フォーマットはFreeBSDコマンドのstrftimeに準拠していて、ISO8601ではなくて、RFC822に依存します。
RFC822
zone        =  "UT"  / "GMT"       ; Universal Time
                                              ; North American : UT
            /  "EST" / "EDT"           ;  Eastern:  - 5/ - 4
            /  "CST" / "CDT"           ;  Central:  - 6/ - 5
            /  "MST" / "MDT"          ;  Mountain: - 7/ - 6
            /  "PST" / "PDT"           ;  Pacific:  - 8/ - 7
            /  1ALPHA                 ; Military: Z = UT;
                                             ;  A:-1; (J not used)
                                             ;  M:-12; N:+1; Y:+12
            / ( ("+" / "-") 4DIGIT )    ; Local differential
                                             ;  hours+min. (HHMM)
ということで、HH:MMな表記はHHMMに直さねばなりません。そして%zで受ける必要があります。ちょと不思議なのは、Time::Pieceでこれが出来ないことです。※7/24追記 下記のDateTime::Format::Strptimeはできる
parse_time("2012-07-12 18:00:00 JST", '%Y-%m-%d %T %Z'); # error!
これは自前で±HHMMに置き換えるしか無いのかなぁ。

なおDateTime::Format::Strptimeでも同じような事ができますが、同じく正しいのは一番下のみ下の2つになります。7/24追記※GMTのケースは%Zの前にスペースが無いだけでした
use strict;
use warnings;
use DateTime::Format::Strptime;

sub parse_time {
    my ($time, $format) = @_;
    my $d = DateTime::Format::Strptime->new(pattern => $format)->parse_datetime($time);
    $d->set_time_zone("UTC");
    warn $d->strftime('%Y-%m-%d %T %Z');
}

parse_time("2012-07-12 18:00:00+09:00", '%Y-%m-%d %T+09:00');
#parse_time("2012-07-12 18:00:00 GMT", '%Y-%m-%d %T%Z'); 7/24訂正
parse_time("2012-07-12 18:00:00 GMT", '%Y-%m-%d %T %Z'); 
parse_time("2012-07-12 18:00:00+0900", '%Y-%m-%d %T%z');
問題を解りづらくしていたのは以下の様なコードの時に

eval { Time::Piece->strptime($str, '%Y-%m-%d %T+09:00') } ||
eval { Time::Piece->strptime($str, '%Y-%m-%dT%T JST') }


2011-07-12 18:00:00+09:00のような日付が渡ってきた場合、パースはできるけど、Time Zoneを考慮しないという点でしょう。ちょっとはまりました。

このエントリーをはてなブックマークに追加

↑このページのトップヘ