2007年07月17日

プログラミングのメモ

このプログラミング用のサイトは既に削除しました。
『箱入り娘』の配布場所は、箱入り娘です。
2011.11.28 更新


『箱入り娘』の配布場所を『[プログラミングのメモ]』に移します。

こことは別にプログラミングのメモを書くためのブログも持っている。その名もそのまんま『プログラミングのメモ』。今年の初めに作った。そのことはこのブログにも書いていた。

実はこのメモ、自分でもアドレスを忘れるぐらい放置していた。作ってから二ヶ月ぐらいしたら集中力が完全にとぎれてしまって、しだいに開けることもなくなっていた。

それが先日この雑記帳にあちらのブログで公開していたものについてのコメントをいただいて、はっと思った。が、アドレス思い出せない。とりあえずググってみた。単純な名前なのに意外に順位が高いのに驚きつつ、開いてみると、あまりにも大量のコメントスパムとトラックバックスパムに閉口してしまった。

スパム削除は手作業じゃ無理なので、FTPを使ってログを削除という力業で解決した。そうしてみるとコメントスパムにまぎれて、ちゃんとしたコメントもいただいていた。申し訳ない。

考えてみると、この『箱入り娘』のプログラムもあちらに書くべきだ。こちらはできるだけ文章だけを書いていきたい。少なくともこの一つ前の投稿はこのブログではなく、メモの方に書くべきだ。そういうわけで配布場所を『プログラミングのメモ』に移します。


posted by takayan at 01:22 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2007年12月12日

WindowsのPython用MeCabパッケージを作って、それに対応してみた。

前回の日本語を音素に分解するスクリプトの公開で、Ctypesを利用してMeCabを操作していたのは、Python用MeCabモジュールのWindows版作れなかったから。せっかく公式モジュールがあるのだから今回はこれを使えるようにしてみた。普通に、MeCabサイトからPython用のバインドモジュールをダウンロードできるが、インストールしようとするとコンパイラとしてVC++2003を要求されてしまう。物持ちがよくて現役を退いたVC++2003を用意できたとしても、今度はコンパイルエラーが出てしまう。

理由を調べてみると、「MeCabのPythonバインディングをWindowsでビルド」に書いてあった。MeCab.hを次の差分のように書き換えなくてはいけない。上記のリンク先の変更とは多少違う。
--- mecab.h.original
+++ mecab.h
@@ -216,12 +216,12 @@

virtual ~Tagger() {}

-#ifndef SIWG
+#ifndef SWIG
static Tagger* create(int argc, char **argv);
static Tagger* create(const char *arg);
-#endif

static const char *version();
+#endif
};

/* factory method */


MeCabサイトに行ってソースを持ってきて解凍し、srcフォルダに入っているMeCab.hを上記のように書き換え、SWIGを使ってmecab_wrap.cxxを作り直す。SWIGというのは、バインドのためのコードを自動で作ってくれるソフト。MeCabの公式のPythonバインドもこれを使って生成されている。SWIGサイトからWindows版を持ってきてインストールするmecabソースのswigフォルダで下記のようなコマンドを実行すると、i拡張子のファイルの指示に従って、仲介するコードを作ってくれる。
swig -python -c++ -o mecab_wrap.cxx mecab.i

なおこのswig.exeにはPATHは通っている。以後上記のようなコマンドの例は適切にPATHなどの環境変数が設定されているとする。

そして、「Windows で MeCab python binding をコンパイルする (2006/01/15)」を参考にして、setup.pyも修正する。MeCabのWindows版が標準の場所「C:/Program Files/MeCab/sdk」にインストールされているとすると、次のようになる。
setup(name = "mecab-python",
version = '0.96',
py_modules=["MeCab"],
ext_modules = [
Extension("_MeCab",
["MeCab_wrap.cxx",],
include_dirs=['C:/Program Files/MeCab/sdk'],
library_dirs=['C:/Program Files/MeCab/sdk'],
libraries=['libmecab'])])


このフォルダで次のコマンドを実行するとセットアップが完了する(VC++2003を持っていれば)。
python setup.py install


さて、VC++2003(VC7.1)が要求されるのはどうしてだろう。それはWindows向けのPython2.5がVC++2003でコンパイルされて作られたプログラムだからだ。もっと詳しく言うとPython2.5がMSVCR71.DLLを使っているから。Windowsではコンパイラの種類によって、それで作ったプログラムの使うMSVCRTの種類が違ってくる。そしてその違うMSVCRTを一つのプログラムの中で使おうとすると、ランタイムエラーでプログラムが止まってしまう。Pythonのセットアップスクリプトは、Python本体を作るときに利用したのと同じVC++2003を要求して、モジュールでも同じMSVCR71.DLLを使おうとする。

VC++2003を持っていると、とりあえず上記の改造されたMeCab.hを使って作ったmecab_wrap.cxxをsetup.pyでコンパイルしインストールができる。では持っていない人はどうすればコンパイルできるだろうか。残念ながらVC++2003は販売終了している。同じランタイムでコンパイルしてくれるものに、Visual C++ Toolkit 2003というコンパイラがある。これは数年前までマイクロソフトから無料で配布されていたコンパイラだ。一緒にPlatform SDKをインストールして使う。そのままではsetup.pyでコンパイルできないが、setupを解釈するスクリプトを改造(Python 2.4 Extensions w/ the MS Toolkit Compiler参照)すれば、パッケージを作ってくれる。残念ながらこのVC++ToolKit2003も配布は終了している。

そういうわけで現在ではMSVCRT7.1を使うマイクロソフト純正コンパイラは入手困難となっている。それでも、どうしても入手しなくてはいけないのならば、マイクロソフト社のMSDNに入会することになるだろう。旧バージョンの使用 (ダウングレード) - MSDN。タイムリーにもMSDNへは現在VC++2008発売直前のキャンペーンで少し安く入会できる。 Visual Studio 2008 早期導入キャンペーン 。もう一つ、特定のバージョンを以前買ったことがある人へのキャンペーンも実施されている。Visual Studio 2008 早期導入キャンペーン 〜今なら更新パッケージがお得!〜。でもどちらにしても、仕事で使わない限り、手軽に買える商品ではないので、これは万人の解決法ではない。

ではどうするかというと、MSVCR71.DLLを使うことを諦めて現在入手可能なコンパイラを使ってMSVCRTそのものを使わないモジュールを作ればいい。その組み合わせで問題が起きないかはやってみないと分からないが。Visual C++ 2005 Express Edition 日本語版(VC8)は登録が必要だが無料で入手できる。これもPlatform SDKをインストールして使う。(Visual C++ 2005 Express Edition と Microsoft Platform SDK を一緒に使うを参照)。このコンパイラでも上で作り直したmecab_wrap.cxxをそのままコンパイルすることができる。そのときコンパイラのスイッチとして、/MDではなく/LDを使う(/MTでも良さそうだが今回/MTで動かなかった)。/LDだとMSVCRTを使わないDLLを作る。とりあえずこれで動く。
cl -EHsc /LD /Ox /I "c:\Program Files\MeCab\sdk"
/I "C:\Python25\include" mecab_wrap.cxx
"C:\Program Files\MeCab\sdk\libmecab.lib"
"C:\Python25\libs\python25.lib"
長いので折り曲げて書いてあるが上記を一行で書く。環境変数path、include、libが適切に設定されているとする。上記「MeCabのPythonバインディングをWindowsでビルド」にあるものと同じコード。

でも、誰かがコンパイルしたものを配ってくれれば個々にこんな面倒なことをしなくてもいい。それもMSVCR71.dllに対応したコンパイル済みのモジュールを。MeCabの配布先でついでに公開してもらえると楽なんだけどまだそれはない。調べてみると、setup.pyスクリプトでモジュールのインストールができると、ほんの少しのコマンドラインの変更で配布用パッケージも作ることができるのが分かった。pyhtonにはこのようにパッケージを作る機能も備わっている。いろんな所で見かけたpythonの配布パッケージもそうやって作っていたのかと今回初めて知った。

長々と書いてきたけれど、そういうわけで、setup.pyを使って作ってみた。自己責任でご利用を。
ダウンロード mecab-python-0.96.win32-py2.5.exe

そして、このMeCabモジュールを利用してスッキリした記述にしたpyDaTTL0.6
ダウンロード pyDaTTL06.zip

上記のプログラムを利用するためには、libmecab.dllへPATHが通っていないといけない。手っ取り早い方法は、"C:/Program Files/Mecab/bin"にあるlibmecab.dllを確実にPATHが通っている"C:/WINDOWS/SYSTEM32/"に放り込めばいい。けれど、MeCabを使っていろいろ試してみるにはこのbinフォルダにある他のコマンドが自由に使えた方が楽なので、今後のためにこのbinフォルダをPATHに追加しておいてもいい。


posted by takayan at 01:20 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2007年12月14日

MinGWでmsvcr71.dllを使う方法

前回は、Windows向けPython2.5で使われているのはmsvcr71.dllだということ。そして現在で回っているマイクロソフト製のコンパイラでは、もう世代が変わってしまっていて、そのmsvcr71.dllにリンクするプログラムを作るのはとても大変だということを書いた。

マイクロソフト製以外にもコンパイラはある。Pythonの向けのパッケージはMinGW GCCを使ってもコンパイルできる。これを使うとmsvcr71にリンクするプログラムを作ることができる。

Python限定の話題ではないが「MinGW GCCでlibcとしてmsvcrt.dll以外を使うまとめ」で詳しくまとめられている。MinGW GCCは標準でmsvcr71.dllではなく、msvcrt.dllへリンクするように作られているので、ちょっと工夫しないといけない。その工夫の仕方が書いてある。

記事の最後の方の「もっと根本的に、specファイルを書き換える方法」で紹介されているspecファイルを書き換えたものを用意して、それをコンパイル時に-specで指定する方法が、一番無難な方法じゃないかと思う。常にmsvcr71.dllへリンクしたものを作るというのならば、「C:/MinGW/lib/gcc/mingw32/3.4.5/(バージョン番号は適宜置き換え)」にあるspecsファイル中の-lmsvcrtを-lmsvcr71に置き換えてしまえば、煩わしくなくなるだろう。

ただ、ためしにmecabソースをその設定でビルドしてみるとctype.hの記述が原因でエラー終了してしまった。すべてがうまくいくというわけでもないみたい。

MinGW GCCではVCとはまた別のライブラリを用意しないといけない。VCのライブラリからの変換の手順はいろんなところで紹介されているので、それにしたがって作ればいい。そもそもMinGW環境そのものの構築の仕方は、面倒なので書いていないが、これも検索すれば見つかる。


posted by takayan at 03:29 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2008年04月19日

M3U形式プレイリストを作るWSHスクリプト

テキストエディタで編集できるプレイリストというのは便利だな。ということで、フォルダを放り込んだらそこにある音楽ファイルのリストを作るスクリプトを作ってみた。

選択したファイルやフォルダ内に含まれる音楽ファイルのリストを作ってくれる。曲順が気に入らなければ、メモ帳なんかで開いて、切り取り・貼り付けで動かせばいい。要らない曲は削除すればいい。


免責事項。私takayanは、このプログラムによって生じる一切の不具合、影響などに関する損害は一切感知しません。 それに同意いただいた方のみご利用ください。改変自由です。

↓↓↓ダウンロード
playlistup.zip ver.1.0.1
※冗長なところをちょと修正

解凍ソフトを使って適当な場所で解凍すると二つのWSHのスクリプトが入っている。playlistup.wsfはプレイリストを作るスクリプト本体。sendto.wsfは「送る」メニューに「簡易プレイリストの作成」を登録するもの。WindowsXPでのみ動作確認をしている。

いつものように「送る」メニューに登録して使う。フォルダが一つだけだとその中にプレイリストを作る。ファイルが一つだけか複数のファイルやフォルダのときはプレイリストをそれが置いてあるところに作る。プレイリスト内のファイルは相対パスで表記される。フォルダの中は再帰的に検索される。ファイルは名前順で並べ替えてある。

プレイリストのファイル名はそれが作られるフォルダ名に".m3u"が付いたものになる。既に同じ名前のファイルがあるときは上書きされる。

音楽ファイルかどうかは拡張子だけで判断している。どの拡張子を音楽ファイルと見なすかは、最初の方に宣言している変数extensionsに記述してある。

プレイリストを作る機能はそれぞれのミュージックプレイヤーについていて、マウスで簡単に順序を入れ替えたりできるから、それがちゃんと使いこなせる人にとってはこのスクリプトは不要だと思う。




<job id="playlistup"><script language="JScript">
var extensions = "wav|mp3|wma";
var fs = WScript.CreateObject('Scripting.FileSystemObject');
var args = WScript.Arguments;
if ( args.length == 0 ){
WScript.Echo( 'パラメータがないので終了します' );
WScript.Quit();
}

function filelist( full, path ) {
var list = new Array();
if ( fs.FolderExists( full ) ) {
var folder = fs.GetFolder( full );
var files = new Enumerator( folder.files );
var name = fs.GetFileName( full );
for ( ; !files.atEnd(); files.moveNext() ){
list.push( fs.BuildPath( path,
fs.BuildPath( name, fs.GetFileName( files.item() ) ) ) );
}
var folders = new Enumerator( folder.SubFolders );
for ( ; !folders.atEnd(); folders.moveNext() ) {
list = list.concat(
filelist( folders.item(), fs.BuildPath( path, name ) ) );
}
} else if ( fs.FileExists( full ) ) {
list.push( fs.BuildPath( path, fs.GetFileName( full ) ) );
}
return list;
}

var list = new Array();
var m3ufile;
var args0 = args(0);
if ( args.length == 1 && fs.FolderExists( args0 ) ) {
m3ufile = fs.BuildPath( args0, fs.GetBaseName( args0 ) + ".m3u" );
var folder = fs.GetFolder( args0 );
var files = new Enumerator( folder.files );
for ( ; !files.atEnd(); files.moveNext() ){
list.push( fs.GetFileName( files.item() ) );
}
var folders = new Enumerator( folder.SubFolders );
for ( ; !folders.atEnd(); folders.moveNext() ) {
list = list.concat( filelist( folders.item(), "" ) );
}
} else {
var parent = fs.GetParentFolderName( args0 );
m3ufile = fs.BuildPath( parent, fs.GetBaseName( parent ) + ".m3u" );
for ( var i = 0; i<args.length; i++ ) {
list = list.concat( filelist( fs.GetAbsolutePathName( args(i) ), "" ) );
}
}
list = list.sort();

var re = new RegExp( "\.(" + extensions + ")$", "i" );
var music = new Array();
var data;
while ( data = list.shift() ) {
if ( re.test(data) ) {
music.push( data );
}
}
if ( music.length ) {
var f = fs.CreateTextFile( m3ufile, true );
var data;
while ( data = music.shift() ) {
// WScript.Echo( data );
f.WriteLine( data );
}
f.Close();
WScript.Echo( "プレイリスト「", fs.GetFileName(m3ufile), "」を",
fs.GetParentFolderName(m3ufile), "に作成しました" );
} else {
WScript.Echo( "音楽ファイルはありませんでした" );
}
</script></job>


posted by takayan at 02:32 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2008年12月01日

Copal2 で Markdown を使う方法

ブログで記事を書くとき、見出しや表やリストを作りたいときがある。Wiki記法を使ったことがあると、ブログでもそういう略記ができるマークアップ言語が使えるといいと思う。

実際、自分で設置したブログの場合にはそういう機能がオプションで用意されている場合がある。プラグインを自由に追加できるブログならば、マークアップ言語を記事に変換してくれるテキストフィルタのプラグインを組み込むだけで簡単に実現できる。

では、今この記事を書いている seesaaブログのようなホスティング型ブログを使っていて、自分で機能拡張ができないときはどうすればいいだろうか。

手っ取り早いのは、変換デモページを利用する方法だ。Markdownならば、PHP Markdown: Dingus。ここで変換された結果をコピペすればいい。でも、すべてをデモページに頼るのもいけないのでローカルでできる方法を考える。

PHPやPerlが動くローカルサーバーを起動させておくというのも手だ。上記デモページと似たようなページを作ってやればいい。でも日常的にローカルサーバーが稼働している環境でないかぎり、変換のためだけにサーバーを起動させるというのは牛刀割鶏だし、かえって遠回り。コマンドラインでスクリプトエンジンを直接利用すれば済むことだろう。

コードと、出力されるタグ、そしてどのように表示されるかのプレビュー、この三つを簡単に、WindowsXP上で確認できるアイデアを考えてみた。

必要なのは、copal2と、php.exe。それから、必要なマークアップ言語のスクリプト。そして、多少の手間。

copalは、スクリプト言語を便利に使うための統合環境。公式サイトは、Copal2これは Windows でスクリプトの開発をするとき重宝している。

copal は、Perl、Ruby などのスクリプト言語のプログラムを書くと、その結果を出力してくれる。ちょっと工夫をして、その記法の記述をスクリプトとして与えて、それを解釈させればいい。

WordPress のプラグインについて知識があったので、今回は PHP を使ったが、Perl や Ruby、Python も使えるので、それで記述されたマークアップ言語を使ってもできるはず。

それでは、具体的な作業。

準備

phpのインストール

今回は PHP で書かれたスクリプトを使うので、Windows 上で動く PHP 処理系をダウンロードしてくる。

PHP 公式サイトのダウンロードページから、Windows Binaries をとってくる。分かる人は ZIP でもいいけど、インストーラをダウンロードして、インストールする。

(追記08.12.2)他のスクリプトを書こうと思ってmbstring関数を使おうと思ったら、使えなかった。かなり悩んでインストーラ版には入っていないことが分かった。今回のMarkdownには必要ないけれど、今後PHPでいろいろスクリプトを書いていくならば、ZIP版をインストールした方がいい。そのときは、php.iniも必要に応じて修正する。定義ファイルに書くパスもインストールした場所に書き換える。

Copal2

Copal 2からダウンロード。一緒にPHP用の定義ファイルをダウンロードする。サイトに書いてあるインストール方法を読んで、自分のパソコンにインストールする。そして、インストールされたフォルダのdefsフォルダに、PHP用の定義ファイルを入れる。PHPのインストール場所が違っていれば、実行ファイルのパスExePathを書き換えておく。

copal にもスクリプトを記述するためのテキストエリアはあるけれど、これはちょっと使いにくいので外部エディタを登録する。詳しくは、Copal2オンラインヘルプ:外部エディタとの連携についてを参照。

Copal で1行何か書いた後、Ctrl+E を押すと、保存を促すダイアログが出てくる。ここで保存をすると、そのファイルを登録した外部エディタで開く。それ以後は、その外部エディタで編集する。外部エディタで保存すると、Copal のエディタに反映される。

Copal には他にも便利なオプションが用意されている。設定メニューの環境設定サブメニューの環境設定タブシートにあるホットキーや、実行メニューにあるオートリフレッシュなど。使い慣れたエディタと Copal でもそのファイルを開いておけば、エディタで書いて保存し、定義したホットキーで Copal をアクティブにして、スクリプト実行の F9 を使えば、マウスを触らなくても簡単に変換作業ができる。



他に必要な設定は、ファイルメニューのエンコード設定で、無難なUTF-8にしておく。エディタでもUTF-8で書くようにする。



PHPのテスト

copal と php がインストールされたので、うまく copal で pho スクリプトが動くか試してみる。copal の設定メニューの言語サブメニューを開いて、そこから php を選ぶ。そして、copal のスクリプトウィンドウに、次のコードを記入する。

<?php
print "Hello, World!";
?>

記入したら、F9キーをタイプしてみる。タブが自動的に切り替わって、Hello,World!と表示されたら、これでOK!

Markdown Extra の利用

Markdown Extraのインストール

いろいろなマークアップ言語があるけれど、今回はまず、PHP Markdown Extraを使ってみる。Markdown Extra は 代表的なマークアップ言語 Markdown に表の記法など拡張をおこなったもの。

PHP Markdownからダウンロードする。

Markdown Extra の特徴は、PHP Markdown Extraに詳しく解説されている。

解凍したファイルを、パス名にスペースの入らないところに配置する。例えば、

C:\textfilter

というフォルダを作って、ここに markdown.php を入れる。そして、このファイルを呼び出す次のスクリプトを、cp_markdownextra.php と名付けて、同じフォルダに保存する。

<?php
include_once('markdown.php');
$text = implode('',file($argv[1]));
$text = Markdown($text);
print $text;
?>

ブログ投稿などの自分の目的に合わせて細かな変更をするといい。次の例は Flock のブログエディタ用。改行を<BR>に変換してしまうので。

<?php
include_once('markdown.php');
$text = implode('',file($argv[1]));
$text = Markdown($text);
$flag = FALSE;
$lines = explode("\n",$text);
$text = "";
foreach( $lines as $line ) {
if ( strstr($line,"<pre><code>") )
$flag = TRUE;

if ( strstr($line,"</code></pre>") )
$flag = FALSE;

if ( $flag )
$line .= "\n";

$text .= $line;
}
print $text;
?>

そして、次の内容を markdownextra.def として保存し、copal の defsフォルダに保存する。

[Language]
Name=Markdown Extra
Ext=txt
[Environment]
ExePath=c:\Program Files\PHP\php.exe
Option=c:\textfilter\cp_markdownextra.php
LastFolder=c:\
TempFile=Copal.tmp

Option は cp_markdownextra.php へのパスになっているので、適宜書き換える。必要ならば他のパラメータも。

Markdown Extra のテスト

Markdown Extra で変換するためには、Copal の設定メニューの言語サブメニューで「Markdown Extra」を選択する。

そして、次の Script 領域に次のスクリプトを貼り付け、「スクリプトを実行」(F9)を押して、Result 領域が表示されれば、成功ということになる。

| First Header  | Second Header |
| ------------- | ------------- |
| Content Cell | Content Cell |
| Content Cell | Content Cell |

こうやってできあがった HTML タグを、ブログの HTMLソース用のテキストエリアにコピーし、投稿すればいい。

※ 投稿してみて、予期しない<BR>が余計に追加されていたので、修正して再投稿。



posted by takayan at 00:23 | Comment(2) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

Copal で HTML特殊文字の変換

Copal2 を使った前回の方法の応用。この方法はマークアップ言語以外の変換にも使える。ブログ中の引用でタグが意味を持たないようにHTMLエンティティに変換するときとか。

次の二つのファイルを用意する。それぞれのファイルの置き場所は前回と同じ。

定義ファイル htmlspecialchars.def

[Language]
Name=HTML SPecial Chars
Ext=txt
[Environment]
ExePath=c:\Program Files\PHP\php.exe
Option=c:\textfilter\cp_htmlspecialchars.php
LastFolder=c:\
TempFile=Copal.tmp

スクリプトファイル cp_htmlspecialchars.php

<?php echo(htmlspecialchars(implode('',file($argv[1]))));?>

こんな感じ。いろいろ応用できる。



posted by takayan at 02:01 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2010年08月19日

pythonで文章中のアラビア数字を漢数字に変換するスクリプト

日本語読み上げのための mbtts を久しぶりに書き直したのですが、そこでアラビア数字を漢数字に変換する部分も修正しました。
このスクリプトをもっと簡潔に書くとどうなるだろうと、単純な条件にしてみて、考えてみたのが次のスクリプトです。

#!/usr/bin/env python
# -*- coding: utf8 -*-
import re

char2int = {
u'0' :0, u'1' :1, u'2' :2, u'3' :3, u'4' :4,
u'5' :5, u'6' :6, u'7' :7, u'8' :8, u'9' :9,
u'0':0, u'1':1, u'2':2, u'3':3, u'4':4,
u'5':5, u'6':6, u'7':7, u'8':8, u'9':9,
}

numKanji0 = [ u'', u'一', u'二', u'三', u'四', u'五', u'六', u'七', u'八', u'九' ]
numKanji1 = [ u'', u'', u'二', u'三', u'四', u'五', u'六', u'七', u'八', u'九' ]
numKanji = [ numKanji0, numKanji1, numKanji1, numKanji1 ]

numPlace1 = [ u'', u'十', u'百', u'千' ]
numPlace4 = [ u'', u'万', u'億', u'兆', u'京', u'垓' ]

# 千の桁が1のときの処理:
#
# (a) 全て千
#  例  千万,  千五百万,  一万千,  千
#
# (b) 全て一千
#  例 一千万, 一千五百万, 一万一千, 一千
#
# (c) 四桁のときだけ千。残りは一千
#  例 一千万, 一千五百万, 一万一千,  千
#
# (d) 四桁のときは常に千。百十一の桁が無ければ一千、あれば千。
#  例 一千万,  千五百万, 一万一千,  千
#
# (e) 一万以下の千の桁は常に千。一万以上の千の桁は常に一千。
#  例 一千万, 一千五百万,  一万千,  千
#
# (f) 一万以下の千の桁は常に千。一万以上の千の桁は、百十一の桁が無ければ一千、あれば千。
#  例 一千万,  千五百万,  一万千,  千

def convert_pure_integerstring(match):
source = match.group()
numstr = re.sub( u'[,,]', u'', source )
# numKanji[3] = numKanji0 # (b)
# numKanji[3] = numKanji1 if len(numstr) == 4 else numKanji0 # (c),(e)
s = []
for ch in ((u'0'*((4-len(numstr)%4)&3))+numstr): s.insert(0,char2int[ch])

list = []
while len(s):
temp = u''
for i in range(4):
if s[i]: temp = numKanji[i][s[i]] + numPlace1[i] + temp
list.append(temp)
s = s[4:]

if len(list) > len(numPlace4): return source

result = u'' # (a),(b),(c),(d)
# result = list[0][1:] if list[0].startswith(u'一千') else list[0] # (e)
# result = list[0] # (f)
for i in range(len(list)): # (a),(b),(c),(d)
# for i in range(1,len(list)): # (e),(f)
if list[i]:
if len(list) > 1 and list[i] == u'千': list[i] = u'一' + list[i] # (d)
# if list[i] == u'千': list[i] = u'一' + list[i] # (f)
result = list[i] + numPlace4[i] + result

return result if result else u'零'

def convert_integerstring(string):
if string == None or string == u'': return u''
p = re.compile(u'[0-90-9][0-90-9,,]*[0-90-9]|[0-90-9]')
return p.sub( convert_pure_integerstring, string )

print convert_integerstring( u'10,000,000, 15,000,000, 11000, 1000')

このスクリプトは日本語の文章の中のアラビア数字を漢数字に変換します。小数点数には対応していません。
桁区切りのコンマは、無視します。つまり、でたらめでも構いません。
数字は半角でも全角でも混ざっていても処理します。

(追記 2010/08/20)
「一千」の扱いについていろいろ修正してみました。ありがちな読み方を6通り考えてみました。対応する行を有効にしたり、コメントアウトしたりすれば、読み方を変えられます。他にも読み方の規則はあるかもしれませんが、そのときは応用して修正すればできると思います。

(a)と(b)は、はっきりと違和感がありますので、わざわざ選ぶことはないと思います。(c)はここで最初に書いていた処理で、一番シンプルで、違和感は多少ありますが許容範囲内だと思います。(d)と(e)と(f)は(c)の違和感を補正する方向で考えたものです。条件分岐を入れて補正しているので、ちょっと処理が美しくありません。(d)と(e)と(f)のどれを選ぶかは作り手のちょっとした好みによるでしょう。
(追記終わり)

最速とはいえませんが、すっきり分かりやすいアルゴリズムだと思います。
一カ所、for ch in ((u'0'*((4-len(numstr)%4)&3))+numstr): s.insert(0,char2int[ch]) が分かりにくいかもしれませんが、全角か半角の数字だけからなる文字列を先頭に0で詰め物をして4の倍数の桁にした後、変換テーブルを使って逆順の数値リストに変換しています。


posted by takayan at 22:51 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2010年08月30日

VC++ で UTF-8ファイルがコンパイルできないとき、

先日、VC++で UTF-8で保存されたファイルのコンパイルに失敗して、面倒くさがってSHIFT_JIS版に逃げてしまったたわけですが、今回はその回避策です。

escapize.py
#!/usr/bin/env python
# -*- coding: utf8 -*-
import os
import re

def convert(n):
if not n: return
f = open(n,'r')
data = f.read()
f.close()

d = False
a = ''
for c in data:
if ord(c) >= 0x80:
d = True
a += u'\\x%0X' % (ord(c))
else:
a += c

if d:
print n
f = open(n,'w')
f.write(a.encode('sjis'))
f.close()

def rec_exec(func,p):
if not func: return
for n in os.listdir(p):
f = os.path.join(p,n)
if os.path.isfile(f):
if re.search( '\.(h|c)$', n ):
func(f)
elif os.path.isdir(f):
rec_exec(func,f)

rec_exec(convert,'.')

0x80 以上の文字コードを16進数表記エスケープシーケンスに置き換えていくだけです。そのソースのフォルダに置いて、この Python スクリプトを実行すれば、再帰的にファイルを見つけて変換してくれます。
欠点として、ソースの日本語が読めなくなってしまいます。そのため変換しない原版を別に残しておかないといけません。逆変換のスクリプトを作るという手もありますが、これこそ面倒なので作りません。

とにかく、これで Windows 版の Open Jtalk で UTF-8 版の辞書も使えるようになりました。


posted by takayan at 03:09 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2011年01月27日

GoSenのちょっとした改良

遅くなりましたが、書いておきます。
Sen/GoSen は ChaSen用の ipadic 辞書を変換して使うのですが、ipadicのバージョン2.6.2以降には対応していません。

対応できない原因は何かというと、ChaSen向けのipadicは2.6.2以降から連接表であるconnect.cha内において「その他の語形」を表す連接規則が書かれなくなっているからです。そのため辞書コンパイル中にレアな語形が出てくると対応しきれずにエラーが出てしまいます。Senの場合はエラーメッセージを出しながら処理は続きます。GoSenの場合はエラーが出たらそこで終わりになります。

そのため今回単純な修正をしています。連接表にない語形の組み合わせが出てきたときには、コスト配列から値を読み込まずに、省略時の値を代入することにしています。この修正が望み通りの日本語を作り出せるかどうか不安ですが、とりあえず問題はないようです。

この修正を加えてもGoSenではまた別の問題が出てきます。メタ文字としても使われる「,」と「{」の解釈です。このような記号も2.6.2以降では辞書に登録されているので、辞書を変換するとき不具合が発生します。ChaSen向けのデータをMeCab向けのデータに変換するとき、単語の区切り記号として「,」が使われるのですが、この解析に問題があります。これを回避する処理が必要になります。「{」に対しても特別な処理が必要になります。

これらの修正を加えたソースを以下に置いておきます。前回のAndorid向けのGoSenで利用する辞書をパソコンで作成するときに使ってみてください。
ダウンロード:gosen-t001.zip

辞書の作り方ですが、antが実行できる環境を作り、エクスプローラで展開したフォルダで開き、その中でシフトを押しながら右クリックをしてコンテクストメニューを開き、メニューからコマンドウィンドウを開いて、antと入力してエンターをします。そのあと、エクスプローラでtestdata/dictionaryフォルダを開き、その中でコマンドウィンドウを開いて、antと入力してエンターをすると、辞書のダウンロードとコンパイルが始まります。なおbuild.xml中のipadic.versionプロパティの値を書き換えると、2.6.0以外の辞書もコンパイルできます。


ここまで書いてきましたが、以下のリンクにGoSenの別の修正についての記事があります。先のAndroid用の辞書作成に使わないのであれば、NAIST 辞書が使えるこちらのほうを使ったほうがいいかもしれません。

GAE/J で GoSen を動かして形態素解析

Google App Engine Java で形態素解析器の比較


Sen(GoSen)はChaSen用の辞書をコンパイルして専用辞書を作っていた頃のMeCabを元にして移植されています。したがってそれ以降改良されてきた現行のMeCabと比べるとどうしても見劣りしてしまいます。今回のその他の語形への対処も現行のMeCabが使っているMeCab専用辞書では細かなコストの設定がされているようで精度に違いが出てくるはずです。新しいJava用の形態素解析器が必要だと思います。

IgoGomokuには期待しています。


posted by takayan at 01:13 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする

2012年03月20日

chmファイルを展開するスクリプト

全盲の方に chm形式のヘルプファイルが使い方が分からないと言われました。キーボードだけで、目次の領域から本文の領域へ移れないそうです。そこで調べてみました。

詳しく書かれていたのは次のページです。
アプリケーションソフトのヘルプ(chm形式)を読む情報ボランティアの会(八王子) 障害者支援部会

これをもとに確かめてみると、目次と本文は、F6キーを押すと切り替わります。よく使われている高知システム開発のスクリーンリーダーPC-Talkerでは、特別に専用のショートカットCtrl+Alt+Win+@で切り替えができます。ただしバージョンによっては対応していないものもあるようです。

chmの画面ではAlt+c で通常表示されている目次、Alt+nでキーワード、Alt+sで検索に切り替わります。それぞれの項目でエンターを押すと、対応する本文が表示されるので、F6キーなどで本文に移ります。本文そのものはIEを読むときのキー操作、Ctrlを押しながら下矢印だったりシフトキーだったりで、読ませます。

 

これだけでは物足りないので、そもそもオンラインヘルプが書かれているchmファイルというのは何なのかを調べてみました。結局、Wikipediaの記事 が詳しいです。

結論としては、chmファイルはLZXアルゴリズムという方式で圧縮されたHTMLファイル群でした。試しに、愛用の7-zipで展開してみると、簡単に構成ファイルを見ることができました。何の細工もせず、右クリックでコンテキストメニューを出して、7-zipの「展開」を選ぶだけです。

出てきたファイルを開いてみると、hhc拡張子のファイルが、オンラインヘルプの目次として表示されているものだと分かります。これも中身はHTMLファイルなので、Webブラウザで閲覧できそうなのですが、OBJECTタグを使って項目の情報を指定しているので、うまく表示できません。表示できれば、この目次を使って展開されたそれぞれの本文を閲覧できるはずです。

そこで、正規表現の置換を使って、簡単にこのhhcをhtmlに変換するJScriptのスクリプトを書いてみました。

indexchm.zip

上記のようにCHMファイルのままでもキー操作だけでスクリーンリーダーで読んでくれるので、わざわざこういうことをしなくてもいいのですが、とりあえず作ってみたので、ここに公開しておきます。

・indexchm.wsf がスクリプト本体です。これにchmファイルを与えると、展開し、index.htmlを作って、それがあるフォルダーを開きます。通常はchmと同じ場所に展開しますが、システムフォルダなど書き込み禁止になっているところだとデスクトップに展開します。展開は7zipではなく、hh.exeでデコンパイルしています。
・setup.wsf で送るメニューやデスクトップへのショートカットを登録します。 以前作ったあれと同じです。これでできたデスクトップのショートカットの上にchmファイルを落としたり、chmファイルを選択した状態で右クリックでメニューを出し、送るメニューからこれを選べば展開します。
・unsetup.wsf でsetup.wsf で登録したショートカットを削除します。

さらにテキストに自動変換すればテキストエディタで詳しく読めたり検索できたりできるでしょう。またこうやって構造さえ理解できれば、テキストDaisyへの自動変換や、もちろん合成音声も含めたデータも作れるでしょう。タブキーで目次と本文の移動ができる新しいビューアーの作成など可能性はあると思います。でもその必要性があるかどうか分からないので、今回はここまでにしておきます。



posted by takayan at 02:10 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする
×

この広告は90日以上新しい記事の投稿がないブログに表示されております。