fold

お久しぶりです。
まだ、試行錯誤の後にこんな例題を書き残す程度の能力です。

とある古いPerlのコードの書き直しで、文字列を1文字ずつ、配列に代入して返すという課題がありました。
前は、

#!perl
use strict;
use warnings;
use utf8;
use Encode;
use Jcode;
binmode STDOUT, ":utf8";
binmode STDIN, ":utf8";

sub str_jfold($$);
sub fold_print($);
sub main();

sub str_jfold($$){ # FAILs when processing unicode
  my $str    = shift;       #指定文字列
  my $byte   = shift;       #指定バイト
  my $j      = Jcode->new($str);
  my @result = (); 
  foreach my $buff ( $j->jfold($byte) ){
    push(@result, $buff);
  }
  return(@result);
}

sub fold_print($) {
    my $text = shift;
    my @result = str_jfold($text, 1);
    foreach my $f (@result){
        next if $f eq '';
        print "fold: $f\n";
    }
}

sub main(){
    my $input = <>; 
    my $inputu = decode_utf8($input);
    fold_print($inputu);
}

main();

のような感じだったんですが、出力が

$ perl utf8_fold.pl
Hatena::Diary is like but a bit different from weblog.
fold: H
fold: a
fold: t
fold: e
fold: n
fold: a
fold: :
fold: :
fold: D
fold: i
fold: a
fold: r
fold: y
(...)
$ perl utf8_fold.pl
はてなダイアリーはブログみたいなサービス。
Use of uninitialized value $f in string eq at utf8_fold.pl line 49, <> line 1.
fold: ã?¯
fold: ã?訢
fold: ã?ª
fold: ã??
fold: ã?¤
(...)

と、日本語の入力に対してうまくいきませんでした。
修正したものが、

sub str_nfold($$);
sub str_nfold($$){ #これならunicodeでもOK
    my $str = shift;
    my $mojisu = shift;
    my @temp0 = split(//, $str);
    my @temp1;
    my @temp2;
    for (my $i = 0; $i < $#temp0 + 1; $i += $mojisu) {
        @temp2 = ();
        for (my $j=0; $j<$mojisu; $j++){
            push @temp2, $temp0[$i+$j];
        }
        push @temp1, join('', @temp2);
    }
    return @temp1;
}

sub fold_print($) {
    my $text = shift;
    #my @result = str_jfold($text, 1);
    my @result = str_nfold($text, 1);
    foreach my $f (@result){
        next if $f eq '';
        print "fold: $f\n";
    }
}
# (以下略)

ということで、表示は

$ perl utf8_fold.pl
はてなダイアリーはブログみたいなサービス。
fold: は
fold: て
fold: な
fold: ダ
fold: イ
fold: ア
fold: リ
fold: ー
(...)

となってくれました。

str_jfoldが不成功だった理由

Perlは、5.8.0以降、内部表現の文字コードとして標準でunicodeをサポートする、というか優先して使用するようになったそうです。

その前は、バイト列をバイト列として扱うことができた。古いコードはその時代に書かれたものでした。標準入(出)力のbinmodeをUTF-8に設定すると、内部表現において2バイト〜6バイトのunicodeをASCII文字で表現したものに変換されるので、EUC-JPやShift_JISでの成功率が高かった特定バイト単位での分割には成功しない、と。

なお、文字数については次ぎの説明がみつかりました。

文字数とデータサイズが比例しないため、文字数を調べるには先頭から全データを読み取る必要がある。ただし、Unicodeでは一部の文字を合成によって表現することもできるから(例:「ぱ」は、U+3071のほかにもU+306F U+309Aでも表現できる)、Unicodeを採用する場合、文字列の文字数をその文字列のバイト数から計算できないことは、UTF-8に限ったことではない。

(http://ja.wikipedia.org/wiki/UTF-8)
ふむふむ。

Python (2.x) の文字コードの件(UTF-8エンコーディング端末での標準入出力)

これも通算7-8時間ほど悪戦苦闘しましたが,UTF-8の場合は下記のような感じでいいのではと思います.

出力

http://d.hatena.ne.jp/ziruchi/20090322/p3 にあるように,UTF-8エンコーディングの端末で標準出力する場合,

# -*- coding: utf-8 -*-
print "これはUTF8エンコーディングの日本語文字列"

のようにマジックコメントと普通のprint文を併用して構わないようです.("..."の前にuが付いていないところに注意)
また,http://d.hatena.ne.jp/kakurasan/20100329/p1 からの丸コピーですが,対話モードで,
(注意:UTF-8エンコーディングの端末におけるテスト)

>>> '日本語' == u'日本語'.encode('utf-8') == '\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e'
True

となるので,冒頭のprint文は

print u"これはUTF8エンコーディングの日本語文字列".encode('utf-8')

と同じとなります.

入力

キーボードタイプでの入力方法は色々ありますが,今僕が使っているのは raw_input() です.
raw_input() の場合,取得した文字列はデコードされず BOM*1UTF-8 文字列となります.

内部処理,実践

Python 内部では文字列は処理する時に BOM 無しのものになっていなければなりません.マジックコメント (# coding: utf-8 ) でエンコーディングを指定して,ソースの文字セットも正しくUTF-8を指定してあるなら,u"日本語" が内部処理用文字列になります.
外部の言語処理プログラムのラッパークラスを使う際は BOM 付のままでよいことがあります.MeCabがそれに該当します.
以上をまとめて次に例示します:

# -*- coding: utf-8 -*-
import MeCab
mecab = MeCab.Tagger()

while True:
  str = raw_input('入力: ')
  if len(str)==0:
    break
  print "target stc:", str
  print mecab.parse(str)
  str2 = str.decode('utf-8')
  print str2[0].encode('utf-8')

結果

入力: 今日はいい天気だ。
target stc: 今日はいい天気だ。
今日	名詞,副詞可能,*,*,*,*,今日,キョウ,キョー
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
いい	形容詞,自立,*,*,形容詞・イイ,基本形,いい,イイ,イイ
天気	名詞,一般,*,*,*,*,天気,テンキ,テンキ
だ	助動詞,*,*,*,特殊・ダ,基本形,だ,ダ,ダ
。	記号,句点,*,*,*,*,。,。,。
EOS

今
入力: 

*1:BOM が何なのかを知るには,[http://ja.wikipedia.org/wiki/%E3%83%90%E3%82%A4%E3%83%88%E3%82%AA%E3%83%BC%E3%83%80%E3%83%BC%E3%83%9E%E3%83%BC%E3%82%AF:title=Wikipedia]あたりを関連のページと合わせて読んだ方がわかりやすいと思います.

Python (2.x) で要素から添え字を調べる

(5/26 訂正*1 )
Python のリストの要素から添字を調べるには,リストのメソッドである list.index() を用います.

例えばある配列 keys (文字列が格納されているとする)とある配列 vals (数値とする)の並びが対応しており,vals の最大の値に対応する keys の文字列を取りたい状況だとします.
普通にディクショナリ(Pythonでいう連想配列)を使えよと言われる所ですが,何かの手違いで配列二個になり,ちょっと手直しで済ませたい状況です.
対話モードで,

>>> keys = ['a', 'b', 'c']
>>> vals = [1.0, 2.0, 3.0]
>>> keys[vals.index(max(vals))]
'c'

連想配列でも可能なのですが,却って少し長くなるみたいです.

>>> dic = {'a':1.0, 'b':2.0, 'c':3.0}
>>> dic.keys()[dic.values().index(max(dic.values()))]
'c'

*1:およそ3ヶ月越しの訂正ですが、dictオブジェクトを上書きしてしまってたことには記事書いて1週間以内に気づいていたことは自分のめいyのため申し添えておきます。なら直せよ…

今週のお題「自己紹介をしてみよう」

ああ、ここは日記だった。
そういえば、まともな自己紹介がないのに気付く。プロフィールの欄は「かつて」だし。

気持ち一新も兼ねて、簡単に。

  1. 好きな事 思いつくままにネットで調べもの, Ruby いじり, YouTube あさり, RSS めぐり, 散歩
  2. 名前 (新しい順に) stamona, somonar, incep (インセプ), intercepter, M.Y.
  3. 年齢 ハチロク世代のあたり
  4. ジェンダー 文体とか書いてる事とか見ればご推察いただけるかと存じます。
  5. 使ってるパソコン 主にマック
  6. 興味ある事 ブログの題の通り、言葉とか自然言語処理とかAIとかです。リアルでは自分にわかる範囲内で勉強したりしてます。

まあ、今回のエントリを書いた第一の動機は、 MacBook Air 11インチ欲しい! なんですが・・・笑。

これ、フォーマットとかはないですよね。
このブログは結局5のパソコンの話題や6の自然言語処理に関するメモなんかとかを扱うことになるんだと思います。さすがに4(ジェンダー論)に関する内容は自分には厳しいですね。でも、1.好きな事について書くのは良いんじゃないかなと思っていたり。

とにかく更新周期は長めにまたわかりづらいエントリが増えていくのでしょう(?)。目標低いなあ。

膠着語

wor un nociw
水 の 星

(1/16追記: フレーズの引用元は、アーティスト ∀KIKO 氏の同名の作品集から。)

この短いアイヌ語の名詞句を、人工言語 "lojban" に訳してみると、ひとまず、


(1) le djacu plini
あの/その 水(-的な) 星 (とされているもの)
となる。アイヌ語は head-last な言語なので、日本語と同じく、nociw が修飾される語(主辞)、wor が修飾語、un が「の」の役割を持つ。
文法の規定された言語である lojban では、原則では前方の語が後方の語を修飾する。そのため、(1)の意味は「水的な星」に固定される。
ところが、lojban では、接辞 un「の」にあたるいかなる valsi -- 語(形態素)が無い。
上の例からわかるように、lojban を自然言語の翻訳の中間言語に用いる際、原言語を意味論の上では正しく伝播する可能性があるが、統語論的構造をそのまま保存することは難しい。ただ、実際の翻訳ではそんなことは誰も望まないけど。意味さえわかればいいということで。

冠詞

ところで、上記の例文(1)での le は公式語定義リストである cmavo.txt では


le LE the described non-veridical descriptor: the one(s) described as ...
となっていて、これは冠詞といっていいものであるけれども、自然な言語の冠詞とは異なる性質をもつものであることは、ウィキブックス(ja)/ロジバンの説明する通り。"djacu plini" のような述語 (brivla) は、このような冠詞がつくことによって、項に挿入できる句として扱えるようになる。
この冠詞は the described 表現されたもののための冠詞であり、かつ non-veridical 真実とは限らない、客観性に基づいていない認識であることを表す際に用いられる。
(1)の例の、「水的な星」という日本語解釈は客観的かと言うと、陸の上、乾燥した地域もあるし、水というより氷に閉ざされた場所も存在することから、主観的といえる。

何が素晴らしいか。それは、自然言語の底流を流れる、「名は体を表す」という概念を、さわやかに否定しているところ。(構造的な)曖昧性の排除から危惧されるところの解釈の一意性を回避する道か。