misimasc - client for misimaserver

先日,旧字・旧仮名遣い変換サーバ misimaserver 2.5 をリリースした。misima SOAP Web Service クライアントからのアクセスにおいて,こちらを利用するようにした。辞書の読み込みをすっ飛ばす分,これまでよりもかなり高速に動作するはずである。

SOAP は実はそれ自体の処理(XML パースなど)が重くて misimaserver の改善効果を減らしてしまう。ソケット通信するクライアントで misimaserver を使うと,先に書いたようにパフォーマンスが大幅に改善される。もし Perl 5.8 以上と,ポート番号 34000 で外に接続できるインターネット環境とをお持ちなら,以下に掲げる Perl コード(misimasc)でアクセスするとよい。これは misimaserver の試験用に作ったものである。標準入力から対象テキストを読んで,標準出力に変換結果を書く仕様なので,配布している SOAP クライアントに置き換えて使うこともできると思う。

端末(コマンドライン)で

% misimasc -S yasuda.homeip.net -P 34000 -kyitq -s c < UTF-8テキスト

などと実行すると変換できるはずである。-S-P 以外の引数 (-kyitq -s c) は misima 変換オプションである。

#!/usr/bin/perl
# -*- mode: cperl; coding: utf-8 -*-
# misimasc: misima client connecting by socket to misimaserver
# 2007(c) isao yasuda, All Rights Reserved.
# $Id: insomnia.txt 222 2014-03-27 11:23:12Z isao $
# DESCRIPTION
# -----------
# - misimaserver への電文を組み立てる。
# - misima オプションを <misima_param> と </misima_param> に挿入する。
# - 変換対象テキストをオプションにすぐ続けて連結する。
# - 変換対象テキスト中の改行文字を :#;~ に変換して一行とする。
# - 電文をソケットに送出する。
# - 変換結果中の :#;~ を改行文字に復元する。
# - 変換結果を出力する。
# HISTORY
# -------
# - 2007/12/04 Ver.2.5 初期作成
 
use utf8;                         # UTF-8
use IO::Socket;                   # Socket
use Getopt::Std;                  # コマンドライン引数処理
use File::Basename;               # ファイル名の取得
use Time::HiRes                   # 高精度タイマー
    qw(gettimeofday tv_interval);
 
binmode STDOUT, ":utf8";
binmode STDERR, ":utf8";
 
# 開始
my $ts   = [gettimeofday];        # start time
my $host = 'yasuda.homeip.net';   # 接続先
my $port = 34000;                 # ポート番号
my ($senddata, $moption);         # 送信データ
 
# コマンドラインオプション
my %opts = (
        'S' => '0',               # server hostname
        'P' => '0',               # port number
        's' => '0',               # 旧字変換: しない
        'y' =>  0,                # 用字・用語変換: しない
        'k' =>  0,                # 旧かな変換: しない
        't' =>  0,                # 単純変換: しない
        'm' => '0',               # マーク: しない
        'i' =>  0,                # 連続文字変換: しない
        'n' =>  0,                # 仮名反転: しない
        'x' => '0',               # TeX 変換: しない
        'c' => '0',               # OTF \UTFx 文字
        'h' =>  0,                # 十六進形式変換: しない
        'q' =>  0,                # quiet
        'g' =>  0,                # Germany active: しない
        'b' =>  0,                # BibTeX Compatible: しない
        'v' =>  0,                # Verbose
        'd' =>  0                 # デバッグ: なし
       );
 
if ($opts{'v'}) {
    printf STDERR loggingtime() . " * misimaclient start.\n";
}
 
# コマンドラインオプションから misima パラメータを組立て
Getopt::Std::getopts('s:ym:ktnx:c:hqidgbvS:P:', \%opts) || usage();
foreach my $op (keys %opts) {
  if (($opts{$op}) && !($op =~ /[vSP]/)) {
    $moption .= "-$op ";
    if ($opts{$op} ne '1') {
      $moption .= "$opts{$op} ";
    }
  }
}
$host = $opts{'S'} if ($opts{'S'});
$port = $opts{'P'} if ($opts{'P'});
printf STDERR loggingtime() . " * host: $host; port: $port; parameter:\n"
    if ($opts{'v'});
my $param = "<misima_param>$moption<\/misima_param>";
 
# 標準入力から対象テキストを読む
while (<STDIN>) {
    utf8::decode($_);
    $senddata .= $_;
}
 
# 改行コードを特定文字列に変換しておく
$senddata =~ s/\n/:#;~/gm;
 
# Socket 通信処理
my $socket = IO::Socket::INET->new(PeerAddr => $host,
                                   PeerPort => $port,
                                   Proto    => 'tcp'
                                  ) || die "Cannot connect: $@\n";
binmode $socket, ":utf8";
printf STDERR loggingtime() . " * $param\n" if ($opts{'v'});
print $socket $param . $senddata . "\n";  # 送信
$socket->flush();
$buf = <$socket>;                         # 受信
chomp($buf);
printf STDERR loggingtime() . " * receive:\n$buf\n" if ($opts{'v'});
$socket->close();
$buf =~ s/:#;~/\n/gm;                     # 改行コードを復元
print $buf;                               # 変換結果出力
 
# 終了
printf STDERR loggingtime() . " * misimaclient ended. elapse: " .
    tv_interval($ts) . " sec.\n" if ($opts{'v'});
 
# ロギング時刻取得
sub loggingtime {
    my ($epocsec, $microsec) = gettimeofday();
    my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
        localtime($epocsec);
    return sprintf("%04d/%02d/%02d %02d:%02d:%02d.%06d",
                   $year+1900, $mon+1, $mday, $hour, $min, $sec, $microsec);
}
 
# Usage
sub usage {
    my($prog) = basename($0);
    die <<"EOM";
misima client programm connecting by a socket to misimaserver Ver.2.5
Usage: $prog [-k|-y|-i|-t|-n|-h|-g|-b|-q|-d|-s [opt]|-x [opt]|
              -c [opt]|-m [opt]|-S server|-P port]
  -k       Convert to historical orthography according to dics and rules
  -y       Convert according to youji-yougo dic
  -i       Convert to iteration marks (No marking)
  -t       Convert according to dic of replace (No marking)
  -n       Invert kana (convert hira to kata, kata to hira; No marking)
  -s       Convert to seiji; available alternative options:
      c      UTF-8 characters
      h      HTML numeric references (hex decimal)
      u      TeX OTF package UTF-8 references (hex decimal)
      a      TeX OTF package CID references
      m      TeX Konjaku-Mojikyo package DAIKANWA ID references
  -x       Convert to TeX commands; available options:
      k      Kanbun kundoku format
      u      Cyrillic, Latin, Greek, UTF8 characters to TeX sequences
      f      force TeX convert of UTF8 characters
      x      use extend tables
      r      Cyrillic to T2A sequences
      t      Thai word breaking and TIS-620 hex conversion
      T      Thai word breaking and UTF-8 output
      h      UTF-8 to hex conversion
      i      iterations of multi characters to kunojiten
      a      k, u and i
  -c       \\UTFx option; available alternative options:
      K      Convert JIS to \\UTFK
      C      Convert JIS to \\UTFC (KANTAIJI)
      T      Convert JIS to \\UTFT (HANTAIJI)
  -m       Mark converted string; available alternative options:
      h      HTML tags
      t      TeX control sequence
  -g       Convert Latin diacritical marks to TeX formats in Germany style
  -b       Convert Latin diacritical marks to TeX formats in BibTeX style
  -h       Convert all characters to hexadecimal strings 0xFFFF
  -q       Quiet run
  -d       Debug: Chasen analysys, dictionary entries display.
  -v       Verbose
   *  The programm reads data from stdin and writes to stdout.
EOM
}
# end of file

実行の様子は以下のとおり。-d (デバッグモード) で起動して,形態素解析状況を表示させている。

% cat t.txt
森鴎外はこう言い,内田百間を団扇であおいだ。
僕は黙っていますよ。
% misimasc -S isolde -P 34000 -kyitnd -s c < t.txt
 
[入力]
森鴎外はこう言い,内田百間を団扇であおいだ。
僕は黙っていますよ。
 
[形態素解析]
  森    森(基本形)-7(名詞) [旧]:(無) [用]:(無)
  鴎外  鴎外(基本形)-8(名詞) [旧]:(無) [用]:(無)
  は    は(基本形)-65(助詞) [旧]:(無) [用]:(無)
  こう  こう(基本形)-56(副詞) [旧]:かう 3 [用]:(無)
  言い  言う(基本形)-47-21-4(動詞-五段・ワ行促音便-連用形) [旧]:(無) [用]:(無)
  ,    ,(基本形)-79(記号) [旧]:(無) [用]:(無)
  内田  内田(基本形)-7(名詞) [旧]:(無) [用]:(無)
  百間  百間(基本形)-8(名詞) [旧]:(無) [用]:(無)
  を    を(基本形)-61(助詞) [旧]:(無) [用]:(無)
  団扇  団扇(基本形)-2(名詞) [旧]:(無) [用]:(無)
  で    で(基本形)-61(助詞) [旧]:(無) [用]:(無)
  あおい あおぐ(基本形)-47-11-5(動詞-五段・ガ行-連用タ接続) [旧]:あふぐ 1 [用]:(無)
    [辞書登録語旧仮名変換活用解析]
    - 変換前: |あおい|
    - 出現形: |あおい| 型番号: 11
    - 基本形: |あおぐ|
    - 登録語: |あふぐ|
    - 語幹部: |あふ|
    - 出語尾: |い|
    - 登語尾: |ぐ|
    - 語幹節: 2
    - 語尾長: 1
    - 変換後: |あふい|
  だ    だ(基本形)-74-54-1(助動詞-特殊・タ-基本形) [旧]:(無) [用]:(無)
  。    。(基本形)-78(記号) [旧]:(無) [用]:(無)
  僕    僕(基本形)-14(名詞) [旧]:(無) [用]:(無)
  は    は(基本形)-65(助詞) [旧]:(無) [用]:(無)
  黙っ  黙る(基本形)-47-17-6(動詞-五段・ラ行-連用タ接続) [旧]:(無) [用]:(無)
  て    て(基本形)-64(助詞) [旧]:(無) [用]:(無)
  い    いる(基本形)-48-6-4(動詞-一段-連用形) [旧]:ゐる 1 [用]:(無)
    [辞書登録語旧仮名変換活用解析]
    - 変換前: |い|
    - 出現形: |い| 型番号: 6
    - 基本形: |いる|
    - 登録語: |ゐる|
    - 語幹部: |ゐ|
    - 出語尾: |い|
    - 登語尾: |る|
    - 語幹節: 1
    - 語尾長: 1
    - 変換後: |ゐ|
  ます  ます(基本形)-74-58-1(助動詞-特殊・マス-基本形) [旧]:(無) [用]:(無)
  よ    よ(基本形)-69(助詞) [旧]:(無) [用]:(無)
  。    。(基本形)-78(記号) [旧]:(無) [用]:(無)
 
[出力]
森鷗外ハカウ言ヒ,內田百閒ヲ團扇デアフイダ。
僕ハ默ツテヰマスヨ。
%

なぜポート番号が 34000 か。ミシマ(3.4 万)だからですよ。

付記:
旧字・旧仮名遣い変換サービスはその後限定公開としました。上記コードでのアクセスは現在は不可になっています。