2018年08月15日

言語処理100本ノックでPython入門 #64(後編) - MongoDBの構築


言語処理100本ノック 2015の第7章・問題64です。

前回はMoongoDBをインストールしたので、今日は、実際の問題を解いてみます。

■ 問題

64. MongoDBの構築
アーティスト情報(artist.json.gz)をデータベースに登録せよ.さらに,次のフィールドでインデックスを作成せよ: name, aliases.name, tags.value, rating.value



■ Pythonのコード
import json
import pymongo

def enumdata():
    with open('artist.json', 'r', encoding='utf8') as fin:
        for line in fin:
            jsd = json.loads(line)
            yield jsd

def register():
    client = pymongo.MongoClient('localhost', 27017)
    db = client['MusicBrainzDb']
    artists = db['artists']
    for data in enumdata():
        artists.insert(data)
    artists.create_index([('name', pymongo.ASCENDING)])
    artists.create_index([('aliases.name', pymongo.ASCENDING)])
    artists.create_index([('tags.value', pymongo.ASCENDING)])
    artists.create_index([('rating.value', pymongo.ASCENDING)])


def main():
    register()

if __name__ == '__main__':
    main()

■ 簡単に説明


artist.jsonからJSONデータを一つずつ取り出して、insertメソッドでDBに登録しています。
全てのデータが登録終了したら、create_indexでインデックスを作成しています。

create_indexを先にやるとどうなるのかな? これは試していません。 件数が多いので、終わるまで結構時間がかかります。

■ データが登録されたかを確認

では、データが登録されたのか確認します。

MongoDB Compass ComunityというGUIの管理ツールがあるので、それをインストールします。

インストールのページで、バージョンを選択する場所があるので、そこで、Comunity Editionを選びます。
最初これがわからず、Comunityではないパッケージをダウンロードしてしまいました。

インストールはすぐに終わります。

インストールが終わったら、MongoDB Compass Community を起動します。
接続の画面ではデフォルトのままでDBに接続します。

MusicBrainzDbができているのが確認できます。
左のペインでMusicBrainzDbを選択すると、登録されている内容が見られます。
indexesタブを選ぶと、インデクスが作成されていることがわかります。

  

Posted by gushwell at 21:00Comments(0)

2018年08月08日

言語処理100本ノックでPython入門 #64(前編) - MacにMongoDBをインストール


今日は、言語処理100本ノック 2015の第7章・問題64です。

■ 問題

64. MongoDBの構築
アーティスト情報(artist.json.gz)をデータベースに登録せよ.さらに,次のフィールドでインデックスを作成せよ: name, aliases.name, tags.value, rating.value


■ MongoDBのインストール

まずは、MongoDBをMacにインストールします。
$ brew install mongodb
このコマンドを投入したら、合わせていろんなものがアップデートされました。

ターミナルの表示を眺めてみると
==> Installing mongodb dependency: sqlite
とか
==> Installing mongodb dependency: python@2
とか。

Python@2って、Python2をインストールしたということなんだと思うんだけど、 MongoDBってPython2に依存してるってことなのかな?
よくわかりません。

とりあえず、最後に
==> mongodb
To have launchd start mongodb now and restart at login:
  brew services start mongodb
Or, if you don't want/need a background service you can just run:
  mongod --config /usr/local/etc/mongod.conf

と表示されたので、正常にインストールできたのだと思います。

続けて、
$ mongo --version
でバージョンを見てみます。
MongoDB shell version v4.0.0
git version: 3b07af3d4f471ae89e8186d33bbb1d5259597d51
allocator: system
modules: none
build environment:
    distarch: x86_64
    target_arch: x86_64

■ Pymongoのインストール


続けて、MongoDBをPythonから操作する pymongoをインストールします。
$ conda install pymongo

以下のようなメッセージが出てきたので、yを押して、更新します。
The following packages will be UPDATED:

    conda:   4.5.8-py36_0         --> 4.5.9-py36_0
    openssl: 1.0.2o-h26aff7b_0    --> 1.0.2o-h1de35cc_1

Proceed ([y]/n)? y

まあ、これは、pymongoとは直接の関係はないですね。

■ MongoDBの起動

以下のコマンドでMongoDBを起動します。
mongod --config /usr/local/etc/mongod.conf

■ MongoDBの終了
$ mongo
で、MongoDBのCLIを起動します。

続けて、
> use admin

で管理者権限に移動します。

そして、以下のコマンドでMongoDBを終了させます。
> db.shutdownServer()

exit コマンドでCLIを終了します。
> exit


macOSでMongoDBを使うを参考にさせていただきました。
っていうか、ほとんどそのままです(^^;;

今日はここまで、実際の問題は後日チャレンジします。
  
Posted by gushwell at 22:15Comments(0)

2018年08月05日

言語処理100本ノックでPython入門 #63 - KVSにオブジェクトを格納


今日は、言語処理100本ノック 2015の第7章・問題63を解きます。


■ 問題
63. オブジェクトを値に格納したKVS
KVSを用い,アーティスト名(name)からタグと被タグ数(タグ付けされた回数)のリストを検索するためのデータベースを構築せよ.さらに,ここで構築したデータベースを用い,アーティスト名からタグと被タグ数を検索せよ.

■ どうやって解くか

KVS(Redis)のValueには、オブジェクトも格納できるから、前回とほとんど変わらないコードでいけるんじゃないかな、と思ったのですが、ダメでした。

登録するまではよかったのですが、取得したデータはなぜかシリアライズされたバイト列でした。 このシリアライズされたバイト列をPythonのオブジェクトに戻す方法がわかりません。

しかたないので、jsonにシリアライズしたものを格納して、取り出すときにjsonからデシリアライズすることにしました。

pickleというものを使う方法もあるみたいだけど、そうなると、Python依存のDBになってしまうので今回は却下。もしかしたら、バイト列がpickleオブジェクトだったりするのかも。

db=1 と指定することで、前回までと別のDBにしてみました。

■ 登録するプログラム

import json
import redis

def enumKv():
    with open('artist.json', 'r', encoding='utf8') as fin:
        for line in fin:
            jsd = json.loads(line)
            if 'tags' in jsd:
                yield jsd['name'], json.dumps(jsd['tags'])

def register():
    r = redis.StrictRedis(host='localhost', port=6379, db=1)
    r.flushdb()
    for k, v in enumKv():
        r.set(k, v)
    r.save()

def main():
    register()

if __name__ == '__main__':
    main()

■ アーティスト名からデータを取得するプログラム
import json
import redis

def printTag(r, name):
    v = r.get(name)
    if v != None:
        print('*' + name)
        tags = json.loads(v.decode())
        for tag in tags:
            print("{}\t{}".format(tag['value'], tag['count']))

def main():
    r = redis.StrictRedis(host='localhost', port=6379, db=1)
    printTag(r, 'George Winston')
    printTag(r, 'Mariah Carey')
    printTag(r, '松任谷由実')

if __name__ == '__main__':
    main()

■ 結果

*George Winston
new age 1
folk    1
*Mariah Carey
whistle register        1
rnb     1
pop     1
american        1
pop and chart   1
girl    1
*松任谷由実
fixme label mess        1
likedis auto    1
  
Posted by gushwell at 21:30Comments(0)

2018年08月01日

言語処理100本ノックでPython入門 #62 - KVSの反復処理


今日は、言語処理100本ノック 2015の第7章・問題62を解きます。


■ 問題
62. KVS内の反復処理
60で構築したデータベースを用い,活動場所が「Japan」となっているアーティスト数を求めよ.

■ Pythonのコード
import redis

def countjapan():
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    keys = r.scan_iter()
    count = 0
    for key in keys:
        v = r.get(key)
        if v == b'Japan':
            count = count + 1
    print(count)

def main():
    countjapan()

if __name__ == '__main__':
    main()

■ ちょっと説明

ものすごく力業っぽいコードだけど、Redisが良く分かっていないので、 この方法しか思いつかなかったです。 

この問題のお題が「反復処理」ってあるから、これでいいのだと思うけど... 遅いです。まあ、このコードじゃ仕方ないよね。 

なお、取り出した値は、バイト列なので、b'Japan'で比較しました。


■ Redisサーバーの停止

  それと、Redisサーバーを停止する正しい方法がわからず悩みました。
$ redis-cli
で、Redisのコマンドラインを起動して、そこで、
> shutdown save
とタイプすれば、停止することができました。

このコマンドラインを終了するには、
> exit
とします。  
Posted by gushwell at 21:30Comments(0)

2018年07月29日

言語処理100本ノックでPython入門 #61 - RedisでKVSの検索


今日は、言語処理100本ノック 2015の第7章・問題61を解きます。


■ 問題
61. KVSの検索
60で構築したデータベースを用い,特定の(指定された)アーティストの活動場所を取得せよ.

■ 作成したPythonのコード
import redis

def enumKeys():
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    v = r.get('The Silhouettes').decode()
    print(v)
    v = r.get('The Wanderers').decode()
    print(v)
    v = r.get('桑田佳祐').decode()
    print(v)


def main():
    enumKeys()

if __name__ == '__main__':
    main()



■ ちょっと解説

r = redis.StrictRedis(host='localhost', port=6379, db=0)
v = r.get('桑田佳祐')
でキーに対応する値を得ることができます。

でも、この結果をデバッグで見て見たら、

b'Japan'

となっていて、はバイト列になっているみたいです。

redisの仕様なのかな?

そのため、バイト列から文字列に変換するには decodeメソッドを使ってみました。
    v = r.get('桑田佳祐').decode()
    print(v)


■ 結果
Netherlands
United States
Japan
  
Posted by gushwell at 22:00Comments(0)

2018年07月25日

言語処理100本ノックでPython入門 #60(後編) - RedisでKVSの構築


今日は、言語処理100本ノック 2015の第7章・問題60を解きます。


■ 問題
60. KVSの構築
Key-Value-Store (KVS) を用い,アーティスト名(name)から活動場所(area)を検索するためのデータベースを構築せよ.

■ 入力ファイル

前回、RedisのインストールとPython用Redisモジュールをインストールしたので、コードを書く準備は整いました。
入力ファイルは、以下のようなJSONファイルです。先頭数行分だけを載せます。
{"name": "WIK▲N", "tags": [{"count": 1, "value": "sillyname"}], "sort_name": "WIK▲N", "ended": true, "gid": "8972b1c1-6482-4750-b51f-596d2edea8b1", "id": 805192}
{"name": "Gustav Ruppke", "sort_name": "Gustav Ruppke", "ended": true, "gid": "b4f76788-7e6f-41b7-ac7b-dfb67f66282e", "type": "Person", "id": 578352}
{"name": "Pete Moutso", "sort_name": "Moutso, Pete", "ended": true, "gid": "49add228-eac5-4de8-836c-d75cde7369c3", "type": "Person", "id": 371203}
{"ended": true, "gid": "c112a400-af49-4665-8bba-741531d962a1", "sort_name": "Zachary", "id": 273232, "name": "Zachary"}
{"name": "The High Level Ranters", "sort_name": "High Level Ranters, The", "ended": true, "gid": "c42eed94-e233-44e2-82b8-3ed6dd9bf318", "type": "Group", "id": 153193}
{"begin": {"year": 1956}, "end": {"year": 1993}, "name": "The Silhouettes", "area": "United States", "sort_name": "Silhouettes, The", "ended": true, "gid": "ca3f3ee1-c4a7-4bac-a16a-0b888a396c6b", "type": "Group", "id": 101060, "aliases": [{"name": "Silhouettes", "sort_name": "Silhouettes"}, {"name": "The Sihouettes", "sort_name": "The Sihouettes"}]}
{"ended": true, "gid": "7b4a548e-a01a-49b7-82e7-b49efeb9732c", "sort_name": "Leavitt, Aric", "id": 145773, "name": "Aric Leavitt"}
ここから、"name"と"area"の値を抜き出して、Redisデータベースに登録するという課題です。


■ dbを使う準備

ローカルで動作させているので、以下のようなコードを書いて、Redisに接続します。
import redis
...
r = redis.StrictRedis(host='localhost', port=6379, db=0)
protはデフォルトで6379のようです。Redisを起動した際のメッセージに表示されていました。

db=0 でデータベースの番号を指定するようです。番号指定なんですね。 ちょっと驚きです。名前指定って無いのかしら?


■ dbを初期化

何回もこのコードを実行することを考慮して、以下のコードで、現在選択されているDBのすべてのキーを削除します。
 r.flushdb()

■ dbに値を登録

このプログラムでは、enumKvメソッドを定義して、Key-Valueのペアを列挙しています。 この結果を、setメソッドでDBに登録します。

for k, v in enumKv(): r.set(k, v) 

■ dbの接続を閉じる

やり方がわかりませんでした。もしかして必要無いのかもしれません。


■ 出来上がったPythonのコード

import json
import redis

def enumKv():
    with open('artist.json', 'r', encoding='utf8') as fin:
        for line in fin:
            jsd = json.loads(line)
            if 'area' in jsd:
                yield jsd['name'], jsd['area']

def register():
    r = redis.StrictRedis(host='localhost', port=6379, db=0)
    r.flushdb()
    for k, v in enumKv():
        r.set(k, v)
    r.save()

def main():
    register()

if __name__ == '__main__':
    main()

■ 結果

このプログラムを動かしたら、Macのファンがすごい音をさせて回り始めました。
なかなか終わらないので、席を外して他のことをやって戻ったら、プログラムは終わってました。
すみません、時間は計測してなかったのですが、席を外していたのは10分程度だったように思います。

正しく登録できたかは、次の問題61で確認します。
   
Posted by gushwell at 20:53Comments(0)

2018年07月22日

言語処理100本ノックでPython入門 #60(前編) - Redisのインストール


今日から、言語処理100本ノック 2015の第7章に入ります。

第7章はデータベースの問題です。

■ 問題


第7章: データベース

artist.json.gzは,オープンな音楽データベースMusicBrainzの中で,アーティストに関するものをJSON形式に変換し,gzip形式で圧縮したファイルである.このファイルには,1アーティストに関する情報が1行にJSON形式で格納されている.JSON形式の概要は以下の通りである.

... 長くなるので省略 ...

artist.json.gzのデータをKey-Value-Store (KVS) およびドキュメント志向型データベースに格納・検索することを考える.KVSとしては,LevelDB,Redis,KyotoCabinet等を用いよ.ドキュメント志向型データベースとして,MongoDBを採用したが,CouchDBやRethinkDB等を用いてもよい.

60. KVSの構築
Key-Value-Store (KVS) を用い,アーティスト名(name)から活動場所(area)を検索するためのデータベースを構築せよ.

問題60では、KVSを構築せよということで、Redisを利用しようと思います。

Redisは初めて使うDBです。

■ Redisのインストール

Macにインストールするには、homebrewを使えばいいみたいです。
$ brew install redis

で redisをインストール。以下、その処理結果。
$ brew install redis

... 省略

==> Downloading https://homebrew.bintray.com/bottles/redis-4.0.10.high_sierra.bo
######################################################################## 100.0%
==> Pouring redis-4.0.10.high_sierra.bottle.tar.gz
==> Caveats
To have launchd start redis now and restart at login:
  brew services start redis
Or, if you don't want/need a background service you can just run:
  redis-server /usr/local/etc/redis.conf
==> Summary
🍺  /usr/local/Cellar/redis/4.0.10: 13 files, 2.8MB
いちおう成功したみたいです。あっけなくインストール完了。


■ redisの起動

では起動してみます。
インストールした際のメッセージには2つの方法が示してあるけど、2つめの方法で起動してみます。
ただし、パラメータなしで起動してみました。

$ redis-server
23134:C 21 Jul 17:20:18.729 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
23134:C 21 Jul 17:20:18.730 # Redis version=4.0.10, bits=64, commit=00000000, modified=0, pid=23134, just started
23134:C 21 Jul 17:20:18.730 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
23134:M 21 Jul 17:20:18.731 * Increased maximum number of open files to 10032 (it was originally set to 8192).
                _._
           _.-``__ ''-._
      _.-``    `.  `_.  ''-._           Redis 4.0.10 (00000000/0) 64 bit
  .-`` .-```.  ```\/    _.,_ ''-._
 (    '      ,       .-`  | `,    )     Running in standalone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 23134
  `-._    `-._  `-./  _.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |           http://redis.io
  `-._    `-._`-.__.-'_.-'    _.-'
 |`-._`-._    `-.__.-'    _.-'_.-'|
 |    `-._`-._        _.-'_.-'    |
  `-._    `-._`-.__.-'_.-'    _.-'
      `-._    `-.__.-'    _.-'
          `-._        _.-'
              `-.__.-'

23134:M 21 Jul 17:20:18.736 # Server initialized
23134:M 21 Jul 17:20:18.736 * Ready to accept connections

起動できたみたいです。
メッセージを見ると、
Warning: no config file specified, using the default config.
とあります。

後で、
$ ls /usr/local/etc
ってやってみたら、redis.conf ファイルが存在してました。 たぶん、これが使われているんだと思います。

デフォルト設定がどんなものかは、調べてません。今回は問題を解くことが目的なので、あまり深入りはしないことにします。 

■ Python用Redisパッケージをインストール

次に、Pythonでこのredisを扱いたいので、Python用のパッケージもインストールします。anaconda使ってるので、condaコマンドを使います。
$ conda install redis

これで、redis-4.0.10 がインストールされました。

今日はここまでとします。

----

ところで、Visual Studio Codeのバージョン1.25.1なんですが、メニューが英語表記になってしまいました。 これって日本語に戻すことできないのかな?

「Japanese Language Pack for Visual Studio Code」も入れて、"ja"に設定してるんですけどね...

まあ、英語のままでもいいか。  
Posted by gushwell at 21:35Comments(0)

2018年07月16日

言語処理100本ノックでPython入門 #59 - S式を解析して名詞句を取り出す


今日は、言語処理100本ノック 2015の第6章・問題58を解きます。

いよいよ第6章最後の問題です。
今回は、なかなか手強い問題でした。

■ 問題


59. S式の解析
Stanford Core NLPの句構造解析の結果(S式)を読み込み,文中のすべての名詞句(NP)を表示せよ.入れ子になっている名詞句もすべて表示すること.


■ S式を解析する

S式を簡単に解析できる機能はPythonでは標準で用意されていないっぽいので、仕方がないので自分で解析することにします。

ただし、名詞句を取り出すのに特化したものとしています。解析しながら名詞句を組み立てていくという感じ。

今回は、pyrthonのソースファイルを2つに分割します。 まずは、S式を解析し名詞句を取り出す部分である、NPExtractor.pyファイル。 ソースコードを示します。

import copy

# 文字列をTokenに分解し、列挙する
class Tokenizer:
    def __init__(self, exp):
        self.exp = exp.replace('\n', '')
        self.curix = 0
        self.curr = ''
        self.prev = None
        self.gen = self.getTokens()

    def nextChar(self):
        if self.curix < len(self.exp):
            c = self.exp[self.curix]
            self.curix += 1
            return c
        return 0

    def getTokens(self):
        c = self.nextChar()
        token = ''
        while c != 0:
            if c == '(':
                yield c
            elif c == ')':
                if token != '':
                    yield token
                    token = ''
                yield c
            elif c == ' ':
                if token != '':
                    yield token
                    token = ''
            else:
                token += c
            c = self.nextChar()
        if token != '':
            yield token
        yield None

    def moveNext(self):
        if self.prev != None:
            r = copy.copy(self.prev)
            self.prev = None
            return r
        if self.curr != None:
            self.curr = next(self.gen)
        return self.curr

    # 一つ前に戻す (ただし連続しては呼び出せない)
    def movePrev(self):
        self.prev = self.curr

# Node.parseで利用するコンテキスストクラス
class Context:
    def __init__(self, exp):
        self.tokenizer = Tokenizer(exp)
        self.nplist = []

#<SExpression> :: ( <part>T <sentence> )
#<sentence> :: <word> | { ( <part> <sentence> ) }
#<part> :: ROOT | S | NP | VP | PP | ....

# <SExpression>を表すクラス
class NPExtractor:
    def parse(self, context):
        curr = context.tokenizer.moveNext()
        if curr == '(':
            # <part>を取り出す 取り出したpartは使わない
            context.tokenizer.moveNext()
            # <sentense>のパース
            node = Sentence()
            node.parse(context, False)
            # ) を取り出す
            curr = context.tokenizer.moveNext()
            if curr != ')':
                raise Exception
        else:
            raise Exception
        return ''

# <sentence>を表すクラス
class Sentence:
    def parse(self, context, isNp):
        phrase = []
        # 先読みする
        curr = context.tokenizer.moveNext()
        if curr != '(':
            # <word>の処理 読み取った単語を返す
            return curr
        # { ( <part> <sentence> )  の処理
        while curr == '(':
            # <part>を取り出す
            part = context.tokenizer.moveNext()
            # <sentense>のパース
            node = Sentence()
            w = node.parse(context, part == 'NP')
            # 現在の () の中の句はphraseに追加
            # ∵ (NP (JJ Many) (NNS challenges)) の Many challenges を記録する必要があるから
            phrase.append(w)
            if part == 'NP' and w != '':
                # 名詞句ならば、nplistにも記憶する
                # このpart が  (NP (JJ Many) (NNS challenges)) の NPならば、
                # w には、'Many challenges' が入っている
                context.nplist.append(w)
            # ) の処理
            curr = context.tokenizer.moveNext()
            if curr != ')':
                raise Exception
            # 次を取り出す
            curr = context.tokenizer.moveNext()
        # 先読みした分を戻す
        context.tokenizer.movePrev()
        if isNp:
            # parseが呼び出された時点で処理しているものがNPならば、phraseにある単語を連結し文字列化する
            # 先頭と最後の不要なものを取り除く かなり使わ伎だが...
            while phrase and (phrase[-1] == ',' or phrase[-1] == '' or phrase[-1] == '.'):
                phrase.pop()
            while phrase and (phrase[0] == ',' or phrase[0] == '' or phrase[0] == '.'):
                phrase.pop(0)
            return ' '.join(phrase)
        return ''

このソースファイルには、4つのクラス(Tokenizer、Context、NPExtractor、Sentence)が定義されています。

はじめは、NPExtractor、Sentenceの親クラスであるNode抽象クラスを定義したのですが、よくよく考えたら不要なので削除しました。

何をやっているクラスなのかはコメントを読んでください。 Tokenizer、Sentence の2つのクラスは、NPExtractorの下請けクラスと思ってもらって構いません。

NPExtractorクラスのparseメソッドを呼び出すと、contextで示した一つのS式を解析し、contextオブジェクトのnplistに名詞句のリストを設定していきます。


■ 取り出した名詞句をファイルに出力する

このNPExtractorクラスを呼び出すメインのソースが以下のコードです。
import re
from xml.etree import ElementTree
from NPExtractor import NPExtractor, Context

class NounPhrases:
    def __init__(self, filepath):
        xdoc = ElementTree.parse(filepath)
        root = xdoc.getroot()
        self.parses = root.findall('document/sentences/sentence/parse')

    def extract(self):
        with open('result59.txt', 'w', encoding='utf8') as w:
            for parse in self.parses:
                ctx = Context(parse.text)
                exp = NPExtractor()
                exp.parse(ctx)
                for p in ctx.nplist:
                    s = re.sub('-LRB-', '(', p)
                    s = re.sub('-RRB-',')', s)
                    w.write(s + '\n')

def main():
    nps = NounPhrases('nlp.txt.xml')
    nps.extract()

if __name__ == '__main__':
    main()
こちらでは、XMLファイルからS式(複数)を抜き出し、それをひとつづつNPExtractor.parseを利用して名詞句を取り出しています。 取り出した結果はファイルに出力しています。

今回初めてソースファイルを分割したのですが、
from NPExtractor import NPExtractor, Context
で、同一フォルダのNPExtractor.pyからNPExtractor, Contextをimportして利用できるようにしています。


■結果


結果の一部を掲載します。
Natural language
processing
Natural language processing
Wikipedia
the free encyclopedia
Natural language processing
NLP
Natural language processing
a field
computer science
a field
artificial intelligence
linguistics
the interactions
computers
human ( natural ) languages
computers and human ( natural ) languages
the interactions
linguistics
a field , artificial intelligence , and linguistics
such
NLP
the area

S式解析して名詞句を組み立てる部分ですが、一部、以下のような表示になってしまうので、もうすこし工夫が必要かもしれません。
Moore 's Law

the `` patient ''

general learning algorithms -


余談ですが、2つ目の、``って、大元の英文のテキストファイル「nlp.txt」には無い文字です。
それが、Stanford Core NLPで、nlp.txt.xmlを作成すると、なぜか、ダブルクォーテーションの「”」が「``」に置き換わってしまうんですよね。

たぶん、開始と終了のクォーテーションを明確に分けるためだとは思うんですが...  元のテキストに戻すような処理を書かないといけない時はちょっと面倒です。
   
Posted by gushwell at 22:10Comments(0)