Lightweight Language Lovers
PythonとRubyを比較してみる(JRubyの可能性)
メインフレーム上のCOBOL というと、LLをお使いの方の眼には、まったく融通のきかない対極の存在のように映るかも知れません。 実際、ちょっとした抽出条件の変更でもコンパイル&リンクが必須ですし、変数がまたすべてグローバル変数なので何かと気を使い、全くと言っていいほど「軽さ」はありません。
しかし、私の触っていたIBMのCOBOL環境では、実行時に、内部ソートで呼び出されるDFSORTというソート専門プログラムに以下のようなパラメータを追加で指定することができました。
INCLUDE (1,2,CH,EQ,'A1',OR,1,2,CH,EQ,'B1') OMIT (10,1,CH,EQ,'1')
これは、「1~2桁目の文字項目が'A1'または'B1'のレコードのみ含み、10桁目が'1'のレコードは除外する。」と読みます。この条件は','で区切って自由に続けることが出来ます。この機能のおかげで、例えば「部署コードの○桁目が○のみのリストを大至急」みたいな突然の要求にも対応ができたのです。このことから、
実行時に言語形式で条件指定できると極めて柔軟性が高くなる
ことが分かります。プログラムは通常必要と思われる条件を想定してパラメータ化しておく訳ですが、想定外の条件に遭遇した場合、プログラムを変更するのではなく、専用言語で対応できれば柔軟性を高めることができます。
一般に、コンパイラ形の言語はインタプリタ型言語に比べて実行性能の面では有利ですが、柔軟性は低くなります。
一方、インタプリタ型言語はその逆です。なので、
コンパイラ型の言語で書かれたプログラムに対し、柔軟性が必要な部分だけインタプリタ言語が使えれば両方の長所を組合せられるのでは?
と考えられます。
現在、Javaはエンタープライズ領域におけるメインストリーム言語として非常に枯れており、実績や性能面では全く不安がありませんが、あまりにも複雑化/多機能化しすぎたため、素早く変化することが難しくなってきています。
一方のLLは様々な言語の良いところを貪欲に採り入れ急速に進化していますが、超大規模システムにおける実績ではJavaに劣ります。
に対応
Python でも同様のモジュールが存在するようなのですが http://www.python.jp/Zope/articles/japanese 、
限られた時間の中いろいろ調べたりインストールする時間が惜しく、1から書いてしまいました。
「楽」というのは、この手間のことも言っています。
まず、
class SjisChars $KCODE = "SJIS" KU13 = 0x8740..0x879c KU89_92 = 0xED40..0xEEFC KU115_9 = 0xFA40..0xFC4B GAIJI = 0xF040..0xF9FC
ですが、$KCODE で漢字コードを設定しておくことが出来ます。これにより2バイト文字を解釈してくれます。
from..to で、コードの範囲を範囲オブジェクトとして定義しています。定数は大文字で始めます。
def initialize(chars) @chars = chars @reKisyu = mkRegexp(KU13, KU89_92, KU115_9) @reGaiji = mkRegexp(GAIJI) end def mkRegexp(*ra) ra.map! {|r| "[%s-%s]" % [[r.first].pack("n"), [r.last].pack("n")]} Regexp.compile(ra.join("|")) end
初期化の部分で、インスタンス変数の設定と、コード範囲を表す正規表現オブジェクトの生成を行っています。 Ruby FAQ を見ると、正規表現に漢字を使うことができることがわかります。
コード範囲から、/[始-終]|[始-終]|../ の正規表現を得るのが目的です。
- ra.map! ... 配列の各要素(コード範囲)に{ }を適用して更新。
- { } ...それぞれのコード範囲(|r|)について、開始値と終了値を漢字に変換後、[始-終]の形に編集。
- 先頭と最後 ... r.first r.last
- 数値から漢字に変換 ... pack("n") "n":ネットワークバイトオーダー
- [始-終]の形に編集 ... "[%s-%s]" %
- [%s-%s]それぞれを | で join して目的とする正規表現に変換(Regexp.compile)
def scanSjis @chars.split(//).each {|c| yield c, isKanji(c), isGaiji(c), isKisyu(c)} end def isKanji(c) c.length == 2 end def isGaiji(c) @reGaiji.match(c) != nil end def isKisyu(c) @reKisyu.match(c) != nil end
は、文字列から漢字を考慮して切り出して(split(//))、判定しながら yield しています。
ここは、文字列.scan(正規表現) を使うと簡単なのですが、他のプログラムに組み込んで使う場合、 順序を保ったまま判定結果が返ってきたほうが良いので、このようにしています。
hexprint はおまけです。
あと、isKanji 等も1行で書いてしまえるので、もっと短くしようと思えば出来るのですが、可読性を高めるためある程度のところで止めています。
一番の感想は、「しばらく経ってから見ても読むのが苦にならない」ということです。
構文の細かな部分はともかく、文法的なノイズが少ないので文書を読む感覚で流れるように眺めていくことができ、アウトラインを把握するのが実に楽です。私は、Java を読むと、ところどころひっかかってしまう上に、読む量そのものも多いので、特に書いてからしばらく経つと読むのが辛くなってしまいます。
また、完成するまで何度も書き直したのですが、その際、一旦書いたコード片をためらわずに消して書き直すことができました。「書いては消し々」が躊躇なくできるのです。いろいろな手法が気軽に試せるのは、学習効果という面でもLLの非常に良いところです。