『カラマーゾフの兄弟』で学ぶ自然言語処理（第1回: 前処理編）

本記事では，青空文庫にある『カラマゾフの兄弟 上』 (ドストエフスキー著，中山 省三郎訳)のテキストを使って，自然言語処理の諸技術を概観する(初心者向け)．
Google Colabでの実行を想定する．
[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](http://colab.research.google.com/github/ezoalbus/kara_nlp/blob/master/colab_notes/1_preprocess.ipynb)

今回は前処理編．

## テキストのダウンロードと確認
青空文庫にある[カラマゾフの兄弟](https://www.aozora.gr.jp/cards/000363/card42286.html)ページの"ファイルのダウンロード"からzipファイルのパスをコピーし，ダウンロード&解凍する．

``` py
!wget https://www.aozora.gr.jp/cards/000363/files/42286_ruby_36920.zip
!unzip 42286_ruby_36920.zip
```

すると，`karamazofuno_kyodai_01.txt`が得られる．

まずは，テキストを見てみよう．

``` py
# 青空文庫はShift-JISでエンコーディングされている．
with open('karamazofuno_kyodai_01.txt', 'r', encoding='Shift-JIS') as f:
    raw_txt = f.read()
print(raw_txt)
```

以下のように表示される．

```
カラマゾフの兄弟
上
ドストエーフスキイ
中山省三郎訳

-------------------------------------------------------
【テキスト中に現れる記号について】

《》：ルビ
（例）汝《なんじ》

｜：ルビの付く文字列の始まりを特定する記号
（例）又｜叔父《おじ》

［＃］：入力者注　主に外字の説明や、傍点の位置の指定
　　　（数字は、JIS X 0213の面区点番号またはUnicode、底本のページと行数）
（例）※［＃「需＋頁」、第3水準1-94-6］

〔〕：アクセント分解された欧文をかこむ
（例）〔plus de noblesse que de since'rite'〕
アクセント分解についての詳細は下記URLを参照してください
http://www.aozora.gr.jp/accent_separation.html
-------------------------------------------------------

［＃ページの左右中央］


［＃ここから４字下げ］
誠にまことに汝《なんじ》らに告ぐ、一粒の麦、地に落ちて死なずば、
唯《ただ》一つにて在《あ》りなん、もし死なば、多くの果《み》を結ぶべし。
［＃ここから２２字下げ］
ヨハネ伝第十二章第二十四節
［＃ここで字下げ終わり］
...
```

余計な注釈などがたくさんついていることがわかる．

## テキストの整形
以下，テキストを整形するために関数を定義する．

文字列変換には主に正規表現を用いる．正規表現がよくわからなくなったら，[RegExr](https://regexr.com/)などで調べるとよい．

Pythonでは`re.sub(パターン, 置き換え先の文字列, 元の文字列)`などで文字列を変換できる．
また，以下で，`re.sub`の第一引数の前にrをつけていることに注意(r'string'の形式のものをraw stringとよぶ)．これにより例えば，r'\n'と書いた場合，'\n'は単なる文字列として扱われ，改行の意味をもたない．

``` py
import re

def clean_text(raw_text):
    """
    生テキストからルビ等を除去する．
    """
    # "."は任意の一文字，"+?"は直前文字の一回以上の繰り返しに最短一致 
    text = re.sub(r'《.+?》', '', raw_text)  # ルビの除去
    text = re.sub(r'｜', '', text)  # ルビの始まり記号を除去
    # "*?"は直前文字の0回以上の繰り返しに最短一致
    text = re.sub(r'［＃.*?］', '', text)  # 入力者注を除去
    text = re.sub(r'---[\s\S]*---', '', text)  # ヘッダーを除去
    text = re.sub(r'\n+', '\n', text)  # 無駄に改行しているものを減らす
    text = re.sub(r'　', ' ', text)  # 全角スペースを半角に変換(単なる趣味)
    text = re.split(r'底本：', text)[0]  # "底本"以下を除去
    text = text.strip()  # 両端の連続する空白文字を除去

    return text
```

上の関数を適用すると，

``` py
text = clean_text(raw_txt)
print(text)
```

次のような出力が得られる．(見やすさのために適宜改行を加えている)

```
カラマゾフの兄弟
上
ドストエーフスキイ
中山省三郎訳
誠にまことに汝らに告ぐ、一粒の麦、地に落ちて死なずば、
唯一つにて在りなん、もし死なば、多くの果を結ぶべし。
ヨハネ伝第十二章第二十四節
アンナ・グリゴリエヴナ・ドストイエフスカヤにおくる
作者より
 この物語の主人公アレクセイ・フョードロヴィッチ・カラマゾフの伝記にとりかかるに当たって、自分は一種の懐疑に
陥っている。すなわち、自分は、このアレクセイ・フョードロヴィッチを主人公と呼んではいるが、しかし彼がけっし
て偉大な人物でないことは、自分でもよく承知している。したがって、『アレクセイ・フョードロヴィッチをこの物語
の主人公に選ばれたのは、何か彼に卓越したところがあってのことなのか？ いったいこの男が、どんなことを成し遂
げたというのか？ 何によって、誰に知られているのか？ いかなる理由によって、われわれ読者は、この人間の生涯
の事実の研究に時間を費やさなければならないのか？』といったたぐいの質問を受けるにきまっていることは、今の
うちからよくわかっている。
 この最後の質問は最も致命的なものである。それに対しては、ただ、『御自分でこの小説をお読みになられたら、
おそらく納得なさるであろう』としか答えられないからである。ところが、この小説を一通り読んでも、なおかつ
納得がゆかず、わがアレクセイ・フョードロヴィッチの注目すべき点を認めることができないといわれた暁には、
どうしたものか？ こんなことを言うのも、実はまことに残念ながら、今からそれが見え透いているからである。
作者にとっては、確かに注目すべき人物なのであるが、はたしてこれを読者に立証することができるだろうか、
それがはなはだおぼつかない。問題は、彼もおそらく活動家なのであろうが、それもきわめて曖昧で、つかみ
どころのない活動家だというところにある。もっとも、今のような時世に、人間に明瞭さを要求するとしたら、
それこそ要求するほうがおかしいのかもしれぬ。ただ一つ、どうやら確実らしいのは、この男が一風変わった、
むしろ奇人に近い人物だということである。しかし、偏屈とか奇癖とかいうものは、個々の特殊性を統一して、全般
的な乱雑さのうちに、ある普遍的な意義を発見する能力を、与えるというよりは、むしろ傷つける場合が多い。奇人
というものは、たいていの場合に、特殊で格別なものである。そうではないだろうか？
 そこで、もしも読者がこの最後の主張に賛成なさらずに、『そうではない』とか、『必ずしもそうではない』と
答えられるとすれば、自分はむしろわが主人公アレクセイ・フョードロヴィッチの価値について大いに意を強うする
次第である。というのは、奇人は『必ずしも』特殊なものでも、格別なものでもないばかりか、かえって、どうか
すると彼が完全無欠の心髄を内にもっているかもしれず、その他の同時代の人たちは――ことごとく、何かの風の
吹きまわしで、一時的にこの奇人から引き離されたのだ、といったような場合がよくあるからである……。
...
```

おわり.

## 参照
[【マメ知識】(改訂版)青空文庫テキストからテキスト解析用の名詞リストを作成する](https://qiita.com/makaishi2/items/9a4e517dfa90bcd0ee6e)