2010-09-15

正規表現を使った処理を Ruby と Python で書いてみる

前回、Ruby で書いた「アプリのかけら」を Python で書き直すにあたって、言語による記述の差というか特徴を調べてみることにした。実際には差を調べるというよりは、Ruby でどう書けば Python への書き直しが楽になるかを考えた、というのが正しい。

題材として、正規表現を使った処理を選んだ。正規表現こそ、テキスト処理の真髄だと思うからだ。これが書き直せるなら、他の部分だってどうにかなる(に違いない)。処理の内容は、HTML から class 属性のついたタグの一覧を作る、というものだ。

Ruby で書いてみる

最初の実装の問題点

Ruby では正規表現は言語に組み込まれた型であり、リテラルとして記述することができる。さらには正規表現を使ったパターンマッチに専用の演算子も用意されている。一方、Python では標準添付ライブラリの一部ではあるものの、正規表現を使うには import re と明示的にライブラリを読み込む必要がある。専用の演算子もないので通常のメソッド呼び出しでマッチを行わなければならない。

つまり、Ruby では以下のように書けるが、Python ではこうは書けない。Python に書き直しやすくするためには、正規表現リテラルの使用を止め、またマッチ演算子も使わないようにした方が良い。

/<(\w+)[^<>]*class=[\'\"]([^\'\"]+)[\'\"][^<>]*>/ =~ str

たとえば、↑は以下のように書き直す。

regex = Regexp.compile('<(\w+)[^<>]*class=[\'\"]([^\'\"]+)[\'\"][^<>]*>')
regex.match(str)

このとき、一点、注意すべきことは、Regexp.compile にわたす正規表現の文字列をダブルクォートではなく、シングルクォートで囲むことだ。ダブルクォートで囲んでしまうと、バックスラッシュによるメタ文字がバックスラッシュ記法として扱われてしまい、意図した正規表現にならない。上記の例で言えば、\ww として Regexp.compile にわたってしまう。シングルクォートを使いたくないなら、\w の前にさらにバックスラッシュを足して \\w とすれば良い。後ろの方のクォート文字につけたバックスラッシュは何がメタ文字なのか自信がなくて付けたものだが、元々つけなくても影響がなかったようだ。

Ruby 特有の記述を書き換えたもの

以上を踏まえ、Python に書き直しやすいように書くとこうなる。

書き直したと言っても、Ruby のプログラムとして読みにくくなっているわけではない。

Python に書き直す

先のプログラムを、素直に Python で書き直すとこうなる。Ruby では配列を使っていたところがリストになっていたり(というより、Python のリストは Ruby の配列とほぼ同じ)、Struct で実現していたタプルが Python では専用の表記で書けたりといった細かな差異はあるものの、ほぼ 1 対 1 で書き直すことができた。

書き直しやすくすることの意義

正直言って、他の言語に書き直しやすいような記述にするなんてことに意義はない。言語で用意してくれてる(記述が簡潔になるような)記法をあえて使わないなんて、言語に対する冒涜だと言っても良いぐらいだ。ただ、言語間の書き直し(つまり移植)を行う際に、こういう中間的な段階を経ることで、目的言語に直したときの不具合を減らすことができる。

それにしてもあれだな。今回のようにほとんど同じに書けるのであれば、ライブラリの相互乗り入れぐらいは実現できないものかね(言語の統合は無理だろうが)。両方とも JavaVM の上で動くもの(Jruby と Jython)ならできるのか? まあ、差が目につかないのは、今回の例が(とても)短いプログラムだからかもしれないが。

関連リンク

関連記事

0 件のコメント:

コメントを投稿