rubyが激しくメモリを消費する件についてです。
だいたい以下のような感じのコードを動かしていたのですが、あっというまにbad_allocを吐いて落ちる。
topを見ていたらメモリを消費する消費する・・・・・
しょうがないのでこういうコードを付け足しました。
これで大分マシになりました。
けどこれでも少しずつメモリを浸食してる。
ううーむ。
最近twitterでXSSによる攻撃があって大騒ぎだったというのがよく話題になっているようです。
自分も実は某社でwikiのような記法を使って記事が書けるwebサイトを作っているのですが、よく考えないで正規表現でごりごり実装したのでXSSを連発して苦い経験をしました。
そこで今日は、文法とか言語についてだらだらと書きます。
(ちなみに計算機系の学部では、授業で形式言語とか正規文法とかならうと思いますが、それです。)
wiki記法は文脈自由文法だと思ってパースした方がわかりやすいかも?
結局記法パーサをど根性で正規表現を駆使して書いたんですが、よく文法構造を考えてみればもっと簡単にパースが出来ただろうことに最近ふと気づきました。
細かい話は端折りますが、大抵のwiki記法というのは文脈自由文法というもので表現できそうです。
文脈自由文法で生成される言語というのは、正規表現では記述できない文があるので、どうしても無理矢理な実装になってしまうようです。(チョムスキー階層)
文脈自由文法と正規表現をメールアドレスを例にわかりやすく書いてる記事があったのでとりあえずそれをご紹介。
なるほど。確かに入れ子構造とかがあると正規文法よりは文脈自由文法であると考えた方がみやすそうです。(ただしメールアドレスは正規表現だけでかけるようです。)
wiki記法には、例えばテーブル要素などの、入れ子構造を持ったものがあるので正規表現だけでごりごりやっていくのはなかなかに難しそうです。
twitterの文法は何だろな
で、twitterなんですが、基本的に入れ子構造がない文法なのであれはどうやら正規文法である気がします。
なので基本的には正規表現ですっきり記述可能なはずです。(※一行の正規表現でかけるという意味ではありません)
一般的な構造テキストの解析の仕方
構造化テキストの間違ったエスケープ手法についてや(Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法についてでも軽く触れられてますが、もうちょっとはっきりまとめるとこういう風につくるのが一般的である様に思います。コンパイラのつくりに似てる気がする。(ある意味これもコンパイルなわけですが)
ちょっとコードを書くのが面倒なので(Twitter の XSS 脆弱性に関連して) 構造化テキストの正しいエスケープ手法についてから拝借します。
CODE:
my $html = ''; for my $token (split m{(http://[0-9A-Za-z_\.\%\?\#\@/]+|\@[0-9A-Za-z]+)}, $tweet) { if ($token =~ m{^http://}) { $html .= '<a href="' . encode_entities($token) . '">' . encode_entities($token) . '</a>'; } elsif ($token =~ m{^\@(.*)$}) { my $user = $1; $html .= '<a href="http://twitter.com/' . encode_entities($user) . '">' . encode_entities($token) . '</a>'; } else { $html .= encode_entities($token); } }
このコードで説明をすると、for my $tokenの行が字句解析にあたり、そのあとのif, elsif, elseの部分が構造解析と出力生成になっています。
ところで、さっきtwitterの記法は正規文法らしいとかきました。
その意味するところは、凄くおおざっぱに言えば、左から順番に解析していけば いいということです。
つまり、処理したトークンをあとで後方参照する必要がありません。
実際先ほどのコードを見てみると、分割したトークンを順番に処理していけばいい形になっているのがわかるかと思います。
結論
最近自分で実装したwikiパーサで結構後悔してたのもあるんですが、余程ややこしい記法でも、大概の場合、文法を意識して字句解析・構文解析をすればすっきり解析できる様に思います。
もし独自の記法をつくりパーサなどを実装することなどがありましたら、ぜひこういったことを思い出してつくってみてください。
※追記:
なんか「エスケープが間違ってた」的な話が多い気がするのだけど、個人的には字句解析とか構文解析の失敗であって、別にエスケープは失敗していない様に思う。
わかりやすく言えば、エスケープ関数にエラーはないわけで(多分
先日twitterをやめたんですが、割りと大きな理由としては、皮肉っぽい発言が多い私がtwitterを使うと敵ばっかり増えて粘着されて(自業自得)気分も悪くなるからだったりします。
けど一方でtwitter見ててもあまり面白く無いなぁと思ったのもあります。
その上、色々考えた結果、あんまり俺も面白いこと書けなくなってるなぁと凄く自省しました。
(もとが面白かったかは知らないけど・・・・多分いまよりは大分ましだった気がする)
書かなくなった
で、それはなんでかなぁと考えたんですが、原因のひとつには「書かなくなった」ことである気がしました。
以前は一日中プログラム書いたり、文章書いたりメール書いたり一日中してたんですよね。
半分は受託開発関連だったので、必ずしも好き好んで書いていたわけではない(HTMLとCSSは未だに嫌い)ですが、今と比べればそらもう一日中怒濤の様に何か書いてました。
なんで書くと面白くなれるのか
プログラミングでも文章でも色々書いたりして、そのために色々調べたりすると色々と小ネタがたまるんですよね。
javascriptのブラウザ間の差異を吸収するためのbad know-howとか、railsの中見てみたら"Spellだらけ"でよくわからなかったとか。
ビジネスプランを書いていれば、送金事業の規制緩和に関する法律改正とかにくわしくなったりとか。
こういうのをブログのネタにしたり、飲み会で話したりとかすると結構これがウケるわけです。
なんでそれがウケるのかというのをちょっと考えてみました。
たぶんそれはこういう理由からだと思います。
つまり、何か目的を持って「書こう!」と思い、様々なことについて体験したり調べたりしたことは、単なる思いつきの感想文よりは面白い何かを含んでいるということなんだと思います。
久しぶりに書いてみると、これが意外に難しい
色々言ったみたものの、この文章は基本的に感想文なんですが(ぉぉ
じゃぁちょっと、まとめて特定のことについて書いてみようかなと思って筆を執ってみたんですが、実にこれが結構難しい。
最近だと、某会社に長く関わってるので開発上の注意点みたいの(デプロイどうしようとかタスク共有どうしようとか)は色々と事細かに語れますが、それ以外のことは中々難しいなと感じました。
そういえば、シュウカツの面接でこれプレゼンしたら大分感心されたので、きっとそれなりに面白かったんでしょう。
結局どういうことなのかと言えば、目の前に起こっている問題に対して自分なりに仮説を立てて本を買ったり対策を講じていたり、プレゼン資料を作ったりしていたのです。
そういう「書く」努力をしていたことに対しては、割りと容易に面白いことがかけるのかもしれないなという風に思いました。(トートロジーですが 苦笑)
面白いひとになるためには普段から書く癖を付けよう
結局おもしろい人間になるためには普段から物事を書く習慣をつけ、調べたりまとめたりすることが必要なのかなということを9月3日くらいに思いました。
書くというのは何も文章ではなくても良くて、プレゼンだったりプログラムだったりスピーチだったり、そういう特定の目的にそってまとめあげる形のものが良い様に思います。
すくなくとも、私が「これは面白いな」と感じるものはニュースサイトやはてブのURLをコピーして140文字程度の感想をつけたものではないようです。
その人の興味や関心に基づいて、少なくとも2つ以上の情報源を元に、一定上の時間をかけてある、感想以上の知見を得られるものです。
何となくそう言うことを思いました。
参考リンク
Dangerous Ideas: Getting Started is Overrated
最近始めたこと
修士論文を真面目に視野に入れ始めたというのもあるのですが、プライベートなpukiwikiを作って、そこに色々なネタを書き貯める様にし始めました。
基本的に「日誌」を毎日簡単に書き、特定の関心事には個別のページを作り#relatedでまとめて行く様にしています。
まだ効果が出てるのかは謎ですが、きっとtwitterにバラバラ書いていることよりは面白いことをたくさん書いている気がします。