作者: davi
日時: 2009/3/05(20:57)
Bruce.さん みなさん < こん??は でび@これからVistaインスコ作業 です

On Thu, 05 Mar 2009 20:37:56 +0900
"davi" <davi-1984@...> wrote:

> この話題のずっと先には、「翻訳ソフトは、内部でどんな
> 処理をしているんだろう?」という疑問があります。
> 
> そんな話題をabcでやるのが適切かどうかはわかりません。

「考え方としてはこうなのかな?」と、以下のように考えてみました。

例文:
------------------------------------------------------
Long long ago, there lived a kind fisherman called "Urashima".
One day, he saved a turtle which had been being tormented by his village children.
When several days had passed, that turtle came to him from the "Dragon Palace".
The turtle took him on the back to the Dragon Palace under the sea.
At the Dragon Palace, he met a beautiful princess.
He had never met such as a beautiful lady so far.
She said, "Mr. Urashima, please enjoy here as long as you wish.".
Urashima forgot the passing of long time.
------------------------------------------------------
ま、こんな例文があったとします。

こいつを、語順は英文のままで構わないとして、逐語対訳をしたいとします。

例えば、一行目だと、

入力:
Long long ago, there lived a kind fisherman called "Urashima".

出力:
昔々、 そこに:そこへ 生きる:住む:生活する 【過去形:受け身】
一つの 種類:優しい 漁師 呼ぶ 【過去形:受け身】 『浦島』。

こんな感じ。

これを、なるべくイリーガル処理を挟み込まない、単純な置換処理で
済ませたいわけです。

使用する言語は、sedやawk、或いはJavaScript,VBS程度の(WinなOSに
インストーラ不要でレジストリいじらないでインストールできる)、
私のような、頭の固い万年初級者でも、ごく普通に使えそうな
ワンライナー的な簡易言語を想定します。

あ、もっとザックリ言えば「コアなファンが布教活動をしていない言語」
と言えばいいのかな…。(敵を増やしそうな言い方で申し訳ない
ですが、他意はありません。)

JavaScriptやVBSなら、たいていのことは何でもできるじゃん、
というツッコミもあると思いますが、私がどうにか理解できるのは、

*ある程度の(Perl並みに複雑ではない)正規表現
*getlineとsprit
*ループ処理とかの、ごく基本的な構文
*配列や連想配列(または「配列の配列」)

という程度なわけです。

ですから、「配列とポインタは別なんだよ」とかの、脳味噌ウニに
なりそうなこと言われてもわかんらんわい、と言いたいワケです。

さて、例えば前処理は以下のような感じかな、と考えました。

y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/
s/\,/、/g
s/\.$/。/g
s/\"([^\"]+)\"/『\1』/g
s/\’([^\’]+)\’/「\1」/g
s/\.([」』])/。\1/g
s/ed\ /\ 【過去形:受け身】\ /g
s/d\ /\ 【過去形:受け身】\ /g
s/est\ /\ 【形容詞最大級】\ /g
s/es\ /\ 【複数形】\ /g
s/s\ /\ 【複数形】\ /g
s/ly\ /\ 【副詞化:〜っぽい】\ /g
s/al\ /\ 【形容詞化:〜な】\ /g
s/er\ /\ 【名詞化:〜する人/形容詞比較級】\ /g
s/tion\ /\ 【抽象名詞化】\ /g
s/ing\ /\ 【進行形:〜している・名詞化:〜すること】\ /g
s/ive\ /\ 【形容詞化:〜の関連の・〜しがちな】\ /g

# 以下、単なる全角化(この例ではまだ網羅してませんが)
s/(\ )+/\1/g
s/\!/!/g
s/\"/”/g
s/\#/#/g
s/\$/$/g
s/\%/%/g
s/\&/&/g
s/\(/(/g
s/\)/)/g
s/\*/*/g
s/\////g
s/\-/―/g
s/\:/:/g
s/\;/;/g
s/\?/?/g
s/\@/@/g
s/\+/+/g
s/\</</g
s/\>/>/g

「ed\ 」と「d\ 」のように、もう既に、この段階で置換処理の
記述順を考慮せねばならないことにお気づきだと思います。

# つーか、上の例の段階では、まだ網羅していないと思いますが、
# 複数形とか格変化への対応ってだけでも、すげー面倒ですね。
# 
# 初期の大規模コーパスとして著名なブラウンコーパスは、実は、
# 単数形と複数形を別単語として計量したというメリケン風の
# 大雑把処理をしていたらしいですが、なるほど、こりゃ、面倒だ。

さて、英文は基本的に1バイトスペースで単語区切りされます。

ですので、今回は、それを利用するという、他の言語体系には
適用不可能な、非汎用的な手法を採用しています。
(が、本心では、それもまた気にくわない。)

まぁ、そんな前処理を経て、その次に、別途、ユーザが作った
対訳辞書ファイルを用いて、逐語訳をするとします。

今、問題点がわかりやすいようにするため、「仮に」対訳辞書は
字数の少ない順で同じ字数の場合はコード順でSortしました。
-----------------------------------------
"a","一つの"
"one","1"
"she","彼女"
"two","2"
"call","呼ぶ"
"kind","種類:優しい"
"live", "生きる:住む:生活する"
"long","長い:永い"
"there","そこに:そこへ"
"one day","ある日"
"urashima","浦島"
"fisherman","漁師"
"long long ago","昔々"
(以下略)
-----------------------------------------

おそらく、対訳辞書の並び順がこれでは問題が生じるはずです。
例えば、例文の末尾2行目にある、
【She】 said, (〜略〜) as 【long】 as

はチャンと訳されるでしょう。

ところが、「long long ago」と「long」は訳し分けたいし、
「fisherman」の中には「she」の文字列や「a」があります。

つまり、対訳辞書ファイルのSort順は、かなり大事な部分なの
だろう…と考えています。

たぶん、対訳辞書ファイル内部のSort順は、

○字数を数え、単語の文字列長が長いもの順にする。
# 同じ文字列長の場合は、どう並べる?とか気になりますが。

最左最長一致がフツーであることを考えると、これが大事に
なってくるんじゃないか?と考えました。

今の例は、たまたま例として1バイトスペースで区切られた
英語なので扱いやすいですが、ASCII文字、非ASCII文字
とかでは区別できない場合は?

例えば日本語の古文を現代語に訳すというような、同じ文字
体系の場合は(chasenとかでの単語区切り処理を前段階で
行わないと仮定して)どうすんの?
 何らかのプレフィクスを付けた文字列のような、中間的な
コード(※)に置換しておいて、それから処理する、という
ような処理をするのが賢い方法?

※PerlならBINモードがあるので特殊なバイト列を作ったり
 すれば良いんでしょうが、今回はそういう複雑な手は使わ
 ないこととします。

こんな所が疑問なワケであります。

でび  http://davi.txt-nifty.com/1984/