Filemaker to Python (3) - 途切れた文字列

前回、PythonからFilemakerのテーブルにアクセスする事に成功はしたのですが、検索した文字列の2文字目以降が途切れてしまうという問題が発生しています。ちなみにODBC側でログを取るオプションを使っても何も吐き出されていませんでした。

ちょっと実験

Select文の検索条件を付けてみましょう。

>>> cursor.execute("select Word, Pinyin from CWordsDB where Pinyin ='ban1 yun4 gong1'")
<pyodbc.Cursor object at 0x100763570>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
搬 ban1 yun4 gong1

やはり、単語(Word)については最初の1文字だけが表示されています。じゃ、検索条件で使うとどうなるんでしょうか?

>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='搬运工'")
<pyodbc.Cursor object at 0x100763570>
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
搬 ban1 yun4 gong1
>>> 

検索そのものは成功している様子。てか文字列変換なしでそのまま行けてるのが軽い驚き。

別のデータではどうなるか?

この「搬运工」という単語、我が単語DBの先頭に乗っているから使っていたのですが、一応他の単語ではどうなるかを検証してみること、意外な事が分かりました。

>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='上海'")
<pyodbc.Cursor object at 0x100763570>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
? shang4 hai3
>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='绅士'")
<pyodbc.Cursor object at 0x100763570>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
? shen1 shi4
>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='搬运工'")
<pyodbc.Cursor object at 0x100763570>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
搬 ban1 yun4 gong1
>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='烈日'")
<pyodbc.Cursor object at 0x100763570>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
? lie4 ri4
>>> 

どうも、どの単語も最初の1文字が表示されるという訳ではなさそうです。例えば、この直前で扱った「烈日」という単語について、生のデータはどうなっているかを拾ってみると、こうなっていました。

>>> row.Word
'\xe7\x83'

中国語の漢字の場合、”\x”で始まる文字列が3ブロック分あって漢字1文字に相当します。しかし、それが2ブロック分しか取得できていない。ということなんでしょうか?

思い切って、全単語を出力してみました。

>>> cursor.execute("select Word, Pinyin from CWordsDB")
<pyodbc.Cursor object at 0x100763570>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
搬 ban1 yun4 gong1
? lie4 ri4
挥? hui1 han4 ru2 yu3
? kan4 zhong4
? fa1 hui1
? ning4 ke3
? mou2 sheng1
? shou3 duan4
? shou4 zui4
? qing1 xiang4
? pin1 ming4
? shi4 dang4
....

漢字によっては、きちんと表示されるパターンもあるようですが、大部分はダメです。

そこで頭をよぎった事がもう1つ。ODBC Adminの中でのSpecial languageの設定です。アレをいじる前は、こんな漢字で出力されていました。

('???', 'ban1 yun4 gong1')

文字化けはしているけど、文字分として認識はされていました。という事が言語設定が逆に悪さをしているのかもしれません。

再び言語設定を変更してみた

f:id:deutschina:20130720165950p:plain

今度は、Treat text type as Unicodeのオプションを外し、Multi-byte text codingにUTF-8を指定してみました。これでどうなるか実験です。

>>> cxcn = pyodbc.connect('DSN=CWord;UID=Admin;PWD=Admin')
>>> cursor = cxcn.cursor()
>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='搬运工'")
<pyodbc.Cursor object at 0x100763c90>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
搬运工 ban1 yun4 gong1
>>> cursor.execute("select Word, Pinyin from CWordsDB where Word ='烈日'")
<pyodbc.Cursor object at 0x100763c90>
>>> rows = cursor.fetchall()
>>> for row in rows:
...     print row.Word, row.Pinyin
... 
烈日 lie4 ri4
>>> 

問題なく動きました。これでいろいろいじる事が出来そうです。

Filemaker to Python (2) - Python側の準備

前の記事の続きです。

pyODBCのインストール

これは、ホントにそのままesay_installであっさり行きました。

$ easy_install pyodbc
Searching for pyodbc
Reading http://pypi.python.org/simple/pyodbc/
Reading http://code.google.com/p/pyodbc
Reading http://code.google.com/p/pyodbc/downloads/list
Best match: pyodbc 3.0.7
Downloading http://pyodbc.googlecode.com/files/pyodbc-3.0.7.zip
Processing pyodbc-3.0.7.zip
Running pyodbc-3.0.7/setup.py -q bdist_egg --dist-dir /var/folders/z_/45w_7yf1701gxyghp070g5t40000gn/T/easy_install-IeVfC3/pyodbc-3.0.7/egg-dist-tmp-6vIccU
warning: no files found matching 'tests/*'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
clang: warning: argument unused during compilation: '-mno-fused-madd'
zip_safe flag not set; analyzing archive contents...
Adding pyodbc 3.0.7 to easy-install.pth file

Installed /Library/Python/2.7/site-packages/pyodbc-3.0.7-py2.7-macosx-10.8-intel.egg
Processing dependencies for pyodbc
Finished processing dependencies for pyodbc

PythonからFilemaker DBにアクセスしてみた

ここまでくれば、あとはPythonからpyODBCを呼んであげて、

$ python
Python 2.7.4 (v2.7.4:026ee0057e2d, Apr  6 2013, 11:43:10) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyodbc

ここからの

>>> cxcn = pyodbc.connect('DSN=CWord;UID=xxxxxx;PWD=xxxxxxxxxx')
>>> cursor = cxcn.cursor()
>>> cursor.execute("select 単語, 拼音 from CWordsDB")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
pyodbc.ProgrammingError: ('42000', '[42000] [FileMaker][FileMaker] FQL0001/(1:8): There is an error in the syntax of the query. (8310) (SQLExecDirectW)')

今、冷静に見ると2つのカラムの間のカンマ(,)が全角になっているのが問題だと分かりますが、とっさにFilemaker側で項目名をアルファベットの名称に変更しました。

で、仕切り直し。

>>> cursor.execute("select Word, Pinyin from CWordsDB")
<pyodbc.Cursor object at 0x100763510>
>>> row = cursor.fetchone()

お、行けた。じゃ、中身を出力してみる。

>>> print row
('???', 'ban1 yun4 gong1')

おっっと。文字化け。1個思い当たるフシが。ODBC AdministratorのAdvanced languageの設定で、Unicodeをオンにしてみる。やっぱり自動言語設定には無理があったかな?

f:id:deutschina:20130720140622p:plain

では、仕切り直し

DSNの設定を変えたので、念のため読み込み直してみる。

>>> cxcn = pyodbc.connect('DSN=CWord;UID=xxxxxx;PWD=xxxxxxxxxx')
>>> cursor = cxcn.cursor()
>>> cursor.execute("select Word, Pinyin from CWordsDB")
<pyodbc.Cursor object at 0x100763570>
>>> row = cursor.fetchone()

良い感じ。では出してみよう。

>>> print row
('\xe6\x90\xac', 'ban1 yun4 gong1')

見覚えのある文字列が出てきたような。でも短くないか?ということで

>>> print row[0]
搬
>>> print row[1]
ban1 yun4 gong1

実際の文字列は「搬运工」なんだけれども、なぜか最初の文字しか拾われていない。

うむ。もう少し調べてみないと分からないな。

(多分つづく)

Filemaker to Python (1) - ODBCドライバを入れてみる

これまでとちょっと毛色の違う話と感じるかも知れませんが、これも技術ネタなのでここに書いておきたいと思います。

なぜいきなりこの話?

先日、中国語の単語のデータベースを持っているという話がありましたが、Filemaker Pro 12のデータベースに入っています。これをCSVに落として、Python+NLTK(ん?NLTKは使ってないかw)で読み込んでいろいろ弄りました。ただ、もう少し簡単にというか、ダイレクトにいじれないかという方法を模索しています。

簡単に考えて、PythonからFilemakerにアクセスすれば良いのではとググってみると、PyFileMakerというのがあったのですが、どうも2008年ぐらいから更新がされていません。その間にFilemakerのリリースも12に上がって、ファイル形式も.fp7から、.fmp12にフォーマットが変わっていて使えなくなったという話も、どこかに目にしました。

となるとこれを使う方法はダメそうです。

それでODBC

その代わりに考えたのがODBCを使う方法です。Filemakerでのファイル共有の方法の1つに、ODBCというのがあり、PythonからODBCにつなぐのには、pyODBCというのがあるのが分かりました。こちらはこの記事を書いている現在でも更新されています。となれば、Filemaker - ODBC - Python (+NLTK)とつなげば行けそうじゃないですか。

pyODBCはeasy_installか何かでインストールすれば良いだろうから、まずはFilemaker側での準備を始めることにしました。Filemakerで出してある良い感じのガイドに素直に従います。

Filemaker ODBC and JDBC Guide

自分の場合は、Filemakerのデータベースを(しかもローカルで)ソースとして使うだけなので、Chapter 3から8に沿って設定すれば良いそうです。

Filemaker ODBCのインストール

ガイドによると、インストールの時に使ったディスクイメージの中にxDBCというフォルダがあって、

f:id:deutschina:20130720105438p:plain

その中のFilemaker ODBC.mkpgというファイルを実行しろと。

f:id:deutschina:20130720105346p:plain

はい、インストール終了。

f:id:deutschina:20130720105842p:plain

ODBC Administratorのインストールと設定

続いては、ODBCの設定をするためのODBC Administratorというのをインストールします。ガイドには、Actual Technologiesというところから出ているODBC Managerというモノの方が先に紹介されていましたが、ODBC AdministratorはAppleが出しているという理由で、こちらを選択しました。ダウンロードしてインストールするあたりは、別に紹介するまでもないと思います。

インストールが終わったら、ODBC Administratorを立ち上げて、User DSNかSystem DSNを追加しろとあります。とりあえず深く考えずにSystem DSN側でAddボタンを押して追加します。

f:id:deutschina:20130720110922p:plain

今のところ選べるのは、当たり前ですがFilemaker ODBCだけなので選びます。

f:id:deutschina:20130720111113p:plain

これはIntroductionなので華麗にスルー。

f:id:deutschina:20130720111209p:plain

データソースにお名前を付けてくださいとのこと。

f:id:deutschina:20130720111322p:plain

ホストネームなりIPを割り当ててという事ですが、今のところローカルでしか使わないのでlocalhostと入れておきます。

f:id:deutschina:20130720111811p:plain

これはFilemaker特有な設定になります。

f:id:deutschina:20130720111952p:plain

Filemakerのどのファイルを参照するのと聞いています。ドロップダウンリストは使えませんでしたが、そのままファイル名をベタ打ちしてやりました。

ここまでやると一通りの手続きが終わったようで、サマリが表示されます。

f:id:deutschina:20130720112203p:plain

一応テストボタンがあったので押してみます。

f:id:deutschina:20130720112235p:plain

大丈夫そうですね。ということで登録完了です。

f:id:deutschina:20130720112258p:plain

(つづく)

Chunking (7.2)

Now I jump to Chapter 7.2

Noun Phrase Chunking (7.2.1)

>>> sentence = [("the", "DT"), ("little", "JJ"), ("yellow", "JJ"), 
... ("dog", "NN"), ("barked", "VBD"), ("at", "IN"), ("the", "DT"), ("cat", "NN")]
>>> grammar = "NP: {<DT>?<JJ>*<NN>}"
>>> cp = nltk.RegexpParser(grammar)
>>> result = cp.parse(sentence)
>>> print result
(S
  (NP the/DT little/JJ yellow/JJ dog/NN)
  barked/VBD
  at/IN
  (NP the/DT cat/NN))
>>> result.draw()

f:id:deutschina:20130720084018p:plain

What I need to understand here is the meaning of grammar. This should be a kind of regular expression. A question mark ('?') is coming after

means
(determiner) is optional. Asterisk ('*') after is at least one time JJ (Adjective, I believe) before NN (Noun).

The result is that found 2 NPs, "the little yellow dog" and "the cat". It was slightly different from my expectation. Let me try some other patterns.

>>> sentence = [("little", "JJ"), ("yellow", "JJ"),
... ("dog", "NN"), ("barked", "VBD"), ("at", "IN"), ("the", "DT"), ("cat", "NN")]
>>> cp = nltk.RegexpParser(grammer)
>>> result = cp.parse(sentence)
>>> print result
(S
  (NP little/JJ yellow/JJ dog/NN)
  barked/VBD
  at/IN
  (NP the/DT cat/NN))
>>>
>>> sentence = [("dog", "NN"), ("barked", "VBD"), ("at", "IN"), ("the", "DT"), ("cat", "NN")]
>>> cp = nltk.RegexpParser(grammer)                                             
>>> result = cp.parse(sentence)
>>> print result
(S (NP dog/NN) barked/VBD at/IN (NP the/DT cat/NN))
>>> 

OK. We can say both

and are optional.

Chunking with Regular Expressions (7.2.3)

>>> grammer = r"""
...     NP: {<DT|PP\$>?<JJ>*<NN>}
...         {<NNP>+}
... """
>>> cp = nltk.RegexpParser(grammer)
>>> sentence = [("Rapunzel", "NNP"), ("let", "VBD"), ("down", "RP"),
...     ("her", "PP$"), ("long", "JJ"), ("golden", "JJ"), ("hair", "NN")]
>>> print cp.parse(sentence)
(S
  (NP Rapunzel/NNP)
  let/VBD
  down/RP
  (NP her/PP$ long/JJ golden/JJ hair/NN))

Now I have recognized that I misunderstood the meaning of '?' and '*' in Regular expression. '?' means 0 or 1, '*' means 0 or larger. In this example, there are two patterns. The first one is similar to the last example but PP$ can be at the beginning as well as DT. The second condition is NNP, proper nouns.

One more example is here.

>>> nouns = [("money", "NN"), ("market", "NN"), ("fund", "NN")]
>>> grammar = "NP: {<NN><NN>}"
>>> cp = nltk.RegexpParser(grammar)
>>> print cp.parse(nouns)
(S (NP money/NN market/NN) fund/NN)
>>> grammar2 = "NP: {<NN>+}"
>>> cp = nltk.RegexpParser(grammar2)
>>> print cp.parse(nouns)
(S (NP money/NN market/NN fund/NN))

There are also two conditions here. The first one (grammar) is defined as NN is repeated twice. As a result, the third NN (fund) was put out of NP. The second one is no limitation to repeat. Therefore all NNs are in NP.

あ、確率の話か (中国語の声調を推測してみる) その3

懲りもせず第3弾の記事です。前回、xin, cheng, gongという音の声調には偏りがあるというデータを出したのですが、もっと顕著な例もあるよというお話しです。

もう一回前提の話

誤解を招きやすい表現なので、きちんと補足しておいた方が良いと思います。今回の分析のネタ元は、HSK6級の試験要綱に載っている全5000語プラス、自分のこれまでの中国語学習テキスト(北京語言大学出版の教科書が中心)から積み上げた1000語強、両者に重複があるのでそれを取り除いて5800語前後の単語から発音と声調のデータを抽出しています。少なくとも中国で中国語を教えるえらい人たちが考える「中国語でもっとも頻出する単語トップ5000」なので、実際にも中国語の中で頻出する単語と考えても差し支えない(と個人的には)判断しています。

で、それらの単語について、発音と声調の組み合わせの頻度をカウントしたデータについて傾向を見ようというお話しです。ちなみに、これらの単語の中には同じ漢字が複数回登場していますが、それらは重複したままカウントされています。

声調が100%決まる音が35種類もあった

一応偶然を排除するために、発音が3回以上登場するものに限定してみたところ、それでも発音に対して一種類の声調しかないものが35種類もありました。

f:id:deutschina:20130715161549j:plain

一例を挙げると、jue, rong, nengはデータの中ではすべて第2声で発音されていて、lie, se, riは第4声でした。一応どんな漢字があるのかというリストもあります。

jue2: 值 决 嚼 掘 绝 觉 (登場回数32回)
rong2: 容 溶 绒 荣 融 (登場回数24回)
lie4: 列 劣 烈 猎 裂 (登場回数20回)
se4: 啬 塞 色 (登場回数18回)

先ほど書いたとおり、同じ漢字が複数回登場しているので登場回数に比べて文字数は少なめです。

全体の2/3の発音は1つの声調が過半数

上の100%は極端だとしても、過半数を占めるものがどのぐらいあるかと計算してみると、全357種類中、241種類の発音、つまり2/3以上の発音は1つの声調が過半数(50.1%以上)を占めていることが分かりました。

我々が特に日本で中国語の発音を習うときは、いろいろな発音を四種類の声調で発声する練習をさせられしますが、このアプローチって、否定はしませんが、実はあまり効率的ではないかも知れないですね。実際には存在しない、またはほとんど使われない発音+声調の組み合わせがかなりの割合で含まれていることになります。

実は、あの声調練習の王様である「ma」の場合でも、頻度で言うと、頻度自体もあまり多くなく、第3声が約50%を占めていて、

f:id:deutschina:20130715165521j:plain

しかも出てくる漢字はこれだけ。

ma1: 妈
ma2: 麻
ma3: 码 马
ma4: 骂

発音の頻度という観点で考えた場合は、「ma」で練習するのは実は効率的ではないかも知れないという訳です。繰り返しますが、否定はしませんけどね。

逆に良く散らばってる音はあるの?

さすがに第1声から第4声まで25%ずつキレイに散らばっているものはデータ上見つかりませんでしたが、tanとかtaoなんかは比較的散らばっている方のように見えます。

f:id:deutschina:20130715173655j:plain

一応、漢字の方も見ておきましょうか。

tan1: 摊 滩 瘫 贪
tan2: 坛 谈
tan3: 坦 毯
tan4: 叹 探 炭
tao1: 掏 涛 滔
tao2: 桃 淘 逃 陶
tao3: 讨
tao4: 套

そろそろまとめを

こうやってデータをこねくり回してきて分かったのは、発音によって声調の偏りがある事は間違いなくて、それは全体の2/3の音に対して1つの声調が過半数占めている事から分かります。なので、ピンインを忘れたときにヤマを張って出す声調を音ごとに決めておけば、恥をかく確率は統計上は下がるはずです。

とは言いつつ、適度に声調が散らばっている音もあるので、それらについては地道に覚えていくしかなさそう。

・・・要は、こんなデータをいじくり回している暇があるなら、まじめに勉強せいと(笑)。

ということで、最後はこれまでに勉強した(日本で出版されている)中国語参考書です。

つながる中国語文法

つながる中国語文法

  • 作者: 林松涛
  • 出版社/メーカー: ディスカヴァー・トゥエンティワン
  • 発売日: 2011/11/16
  • メディア: 単行本(ソフトカバー)
  • 購入: 2人 クリック: 3回
  • この商品を含むブログを見る

Why?にこたえるはじめての中国語の文法書

Why?にこたえるはじめての中国語の文法書


誤用から学ぶ中国語―基礎から応用まで

誤用から学ぶ中国語―基礎から応用まで

冷静にいくら費やしたか考えると、背筋が凍るので今日はこのぐらいにしておこうと思います。