Draw Test Harness 日本語 Wiki 作りました

OpenCASCADE の Draw Test Harness の(ほぼ自分用の)日本語 Wiki を立ち上げるために、以前自分の個人サイトでも利用していた UseMod Wiki を導入することにしました。

UseMode Wiki は、Perl で書かれたシンプルな Wiki システムで、煩雑な設定が少なく、依存関係も少ないので重宝していました。基本部は wiki.pl に全て詰まっており、設定ファイルも一つだけ。
見た目に凝ったり、いろんなことをしようと思えば MediaWiki なんかが良いのでしょうが、そんなに時間も割きたくない、簡単な Wiki 構文が使えればいい、程度でしたら、なかなかオススメの Wiki エンジンです。

そんな UseMod Wiki ですが、Wiki 内のユーザ登録が上手く動作しませんでした。エラー内容を調べてみると、Cookie がどうもちゃんとやり取りできていない模様。公式のヘルプを読んでいると、どうも Cookie の期限が「2013 年 9 月まで」とハードコーディングされているようで、思いがけないところでひっかかっていたようです。(しかも2009年あたりからメンテナンスもされていないみたい)

晴れてユーザ登録し、古い記事を新しい Wiki に移植している途中、今度は一部の記事テキストで、ロリポの 403 エラーが出るようになりました。まるで投稿ができない。
最初は何が原因だか分からなかったので、記事名を変更してみたり、いろいろと試行錯誤していたのですが、どうもロリポが(勝手に)ウェブアプリケーションファイアウォール(WAF)を有効にしていたようで、そこにPOST内容がひっかかっていたみたいです。
ロリポは例の乗っ取り事件を起こしてから、ディレクトリのフルパスを強引に変更したり、トップがアレだったりと、あまり良いイメージではありません。他のところだったら、「ああ、そうか、気付かなかったなー」程度で終わるんでしょうが、ロリポの場合ちょっとだけアレな気分になります。
さくらのVPSも持っているので、WordPressのDBまわりの整理ができたら、dyama.orgの参照先をロリポからさくらに切り替えようと思ってます。(なかなかWordPressを気合い入れて調べる時間がない…。)
さくらのクラウドも石狩のデータセンターが稼動し始めたころ、ちょっと不具合があったみたいですが、それ以前から利用している信頼性はやっぱり高いと思います。

WordPressと言えば、WP-Markdown というプラグインを試してみました。こちらも、「そんな高度なレイアウトや見た目を求めないから、さくさくドキュメントが書ける書式で…」という理由で入れてみたのですが、過去の非 Markdown で書いた記事の Syntax Highlight と相性が悪いみたいで、掲載しているソースコードが HTML 混在の表示になってしまいました。
ひょっとしたら設定がマズいのかもしれませんが、かえって手間がかかるかもしれないので導入を見送りました。

Markdownで記事を書き、gistにコードを貼って、記事からはそれを参照…というのも考えましたが、やっぱりバックアップや以前の記事の取り扱いを考えるとムリかなぁ…。(いや、でも引っ越しは楽そう。githubが潰れない限り!)

Bash, Perl, Ruby, Pythonで正規表現置換

前回のC++/boost.NETに加え、各種インタプリタ言語でも同じ動作をするスクリプトを書いてみました。

シェルスクリプト(bash)

シェルスクリプトはそもそもグルー言語ですので、他のコマンドを呼び出して処理をすることが一般的です。下のサンプルではsedコマンドで置換処理をしています。bashだと正規表現マッチングは可能なので、ガリガリとスクリプトを書けばsedを使わずに実現できるかもしれません。

[bash]

!/usr/bin/env bash

[ $# -ne 2 ] && exit 1
cat | sed -e "s/$1/$2/g"
exit 0
[/bash]

リプレイスメント置換文字は、sedの書式になります。グループ指示子はダラー($)ではなくバックスラッシュ(\)を用いています。

Perl

Perlの場合、正規表現による文字列操作は、関数でもクラスでもなく構文として組み込まれています。その為、コマンドライン引数から渡された「$1」のようなリプレイスメントの展開方法に、若干の工夫が必要です。

[perl]

!/usr/bin/env perl

exit 1 if ($#ARGV != 1);
for (<stdin>) {
eval "s/$ARGV[0]/$ARGV[1]/g" && print;

s/$ARGV[0]/$ARGV[1]/gee && print; # これではダメ

}
exit 0;
[/perl]

リプレイスメントが格納されている$ARGV[1]は展開されると、例えば「$1$2」という文字列になります。この展開後の文字列をリプレイスメントとして正規表現置換の処理に投げたいのですが、正規表現置換処理を行なった後に変数展開されるようでリプレイスメントのグループ指示子としての$nが正規表現置換処理に伝わりません。そこで、正規表現置換処理を行う前に$ARGV[1]を展開させるべく、eval関数に投げています。これにより、正規表現置換処理が評価される時点でリプレイスメントは「$ARGV[1]」ではなく「$1$2」という文字列として解釈され、指示子が正しく伝わるようです。
検索パターンに加え、リプレイスメント文字列も変数で持つという処理は多々あるはずなので、もっとスマートな方法が準備されているのかもしれませんが、性質さえ知っていれば公式を知らずとも期待する処理が可能である、まさに”TMTOWTDI / There’s More Than One Way To Do It(やり方はひとつじゃない)”という設計思想を持つPerlらしい実装です。理に適った挙動は見ていて気持ちがいいです。

Python

Pythonでは、シェルスクリプトやPerlと違って正規表現機能はクラス(re)として提供されています。下のサンプルではreの静的関数を叩いていますが、プリコンパイルしたオブジェクトとしても利用できたと思います。

[python]

!/usr/bin/env python

import sys
import re
v = sys.argv
if len(v) != 3: quit(1)
for line in sys.stdin:
print re.sub(v[1], v[2], line),
quit(0)
[/python]

リプレイスメントのグループ指示子は、sedと同じくバックスラッシュです。Cやシェルライクなエスケープ文字という捉え方をするなら、バックスラッシュがしっくり来ますね。(といっても、ダラーの場合でも同じく「シェルライク」ですけど :D )

ちなみに、len() がオブジェクトのメソッドではなく独立した関数になっているのは、評価対象(上の例の場合は v )が null オブジェクトでも、null チェックなしで利用できるようにする為だとどこかで読みました。Python の場合は空文字列(len=0)は null オブジェクトになるんですね。

Ruby

Rubyの場合は、シェルスクリプトを除いた他のどの言語よりもマニアックな感じがしますが、よく見てみると一番「ナチュラル」に理解し易い構文です。これだけの構文で比較するのはアレかもしれませんが、これだけの構文だけでここまで革新的な要素をたくさん見てとれるのは、rubyだからこそと言った感じでしょうか。ファイルディスクリプタまでオブジェクトであり、イテレータをせおっているあたり、カワイイです。

[ruby]

!/usr/bin/env ruby

if ARGV.size != 2 then exit 1 end
STDIN.each_line do |line|
puts line.gsub(/#{ARGV[0]}/, ARGV[1])
end
exit 0
[/ruby]

Rubyの何十倍もPythonのコードは書いていますが、Pythonは「VB.NETよりも使いものになる、綺麗なVB.NET的な何か」というイメージが拭えません。いいところ、悪いところの両方を知った上で使いこなせていけたらいいなあ、と思いました。

See also

Net::POP3でメール受信

PerlのNet::POP2モジュールを利用したメール受信のサンプルです。このスクリプトをcronに登録し、定期的にメールボックスを確認させて、何かあったらコマンドを実行。なんて用途に使えます。パスワードも平文でのっけているので、セキュリティ的な注意は必要かと思います。

[perl]

!/usr/bin/env perl

use Net::POP3;

sub getmail()
{
my ($server, $user, $passwd, $delete) = @_;
my @result;
my $p = Net::POP3-&gt;new($server) or die &quot;Couldn’t connect to $server.&quot;;
$p-&gt;login($user, $passwd);
foreach $id (keys(%{$p-&gt;list()})) {
push(@result, @{$p-&gt;get($id)});
$p-&gt;delete($id) if ($delete);
}
$p-&gt;quit;
return @result;
}

print &amp;getmail(‘pop.example.com’, ‘example@example.com’, ‘mypassword’);
[/perl]

bsplinecurve コマンド引数( knot 値)を相互変換

NURBS 曲線の knot 値( Bスプライン基底関数を決定する為の値 )は、一般的に下記のように ( 階数 + 制御点数 ) 個の単調増加する配列として表されます。

T = [ 0 0 0 0 1 2 3 3 3 3 ]

一方、OpenCASCADE Draw Test Harness の bsplinecurve コマンドにて上に示す knot 値を持つ NURBS 曲線を生成するには、下記のように指定する必要があります。

0 4 1 1 2 1 3 4

太字部分は knot 値自体を示すのではなく、”直前にある knot 値をくりかえす回数” を示します。Draw Test Harness の公式リファレンスでは誤った記載で引数の解説がなされていた為、少し迷いました。仮に、前者を Plain knots array、後者を Compressed knots array と呼ぶと、下記のような相互変換を行う Perl スクリプトが組めます。

#!/usr/bin/env perl

# Plain knots array to Compressed knots array
# for Draw Test Harness of OpenCASCADE

sub pKnot2cKnot {
  my @pKnot = @_;
  my @cKnot = ( );
  my $bfr = -1, $nb = 0, $i = 0;
  foreach $val ( @pKnot ) {
    if ( $val != $bfr ) {
      $cKnot[$i++] = $nb if ( $i &gt; 0 );
      $cKnot[$i++] = $bfr = $val;
      $nb = 1;
    }
    else {
      $nb++;
    }
  }
  $cKnot[$i] = $nb;
  return @cKnot;
}

# Compressed knots array to Plain knots array
sub cKnot2pKnot {
  while ( length( $val = shift( @_ ) ) ) {
    $buf .= ( "$val " x ( shift( @_ ) ) );
  }
  return split( " ", $buf );
}

このような仕組みを使って、ある三次元 CAD 形式のファイルから Draw Test Harness 経由で、BRep モデルを作成する事が出来ました。ひょっとしたら pKnot2cKnot() は、もう少しスマートに出来るかも。

2020/07/02 追記

度重なるブログ移転・ブログシステムのアップデートにより崩れた記事を校正。ついでに Ruby で書き直してみました。

#!/usr/bin/ruby

def pknot2cknot(str)
  ar = []
  c = 1
  x = nil
  str.split(' ').each_cons(2) do |n, m|
    if n != m
      ar << [n, c]
      c = 1
    else
      x = n
      c += 1
    end
  end
  (ar << [x, c]).join(' ')
end

def cknot2pknot(str)
  Hash[*str.split(' ')].map{|n, m|"#{n} "*m.to_i}.join.strip
end

p pknot2cknot("0 0 0 0 1 2 3 3 3 3") # => "0 4 1 1 2 1 3 4"
p cknot2pknot("0 4 1 1 2 1 3 4")     # => "0 0 0 0 1 2 3 3 3 3"

劇的に小さくなると思いきや、そんなことなかったのが残念。

Array#partition でも Array#group_by でもなく、配列から隣合う要素を比較し、区切りを見つけて多次元配列を返すメソッド…ないかなぁ。

ActivePerl に SDL モジュールをインストールした

確かに SDL を perl で使う人は見たことがない

正直日記

最近はどのデスクトップ用途のディストリにも必ずプリインストールされている程、システムと密接になっている Perl なんだけれども、その Perl を使って、GUI なソフトウェアをごにょごにょしようという動きは、ホント少ない気がする。単純な事をやりたいだけなのに、やれPythonだ、rubyだ、javaだ、と。

続きを読む ActivePerl に SDL モジュールをインストールした

jheadコマンドを使った簡易ギャラリー

jhead はデジカメなどで撮影した画像などに含まれる EXIF 情報を表示してくれるコマンド。debian 系 OS でのインストールは以下のようにする。数百キロバイト程度なのですぐ終わる。

続きを読む jheadコマンドを使った簡易ギャラリー