Colab環境でMeCabを使ってヨミガナを表示する5行

![SS 192.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/565043/a41cd967-f549-8677-1efa-2e99bf69518d.png) 　内包表記を読もうとすると頭がどうにかなる

## やること
 [Colab環境でMeCabを使う3行](https://qiita.com/Ninagawa_Izumi/items/c90cccb453e2a6fc4466
) の補足記事です。

Colab環境でMeCabの出力結果を操る際、MeCab.Tagger()で要素を一旦取得してそこから読みカナなどの結果を抽出するとうまくいきます。
これを５行で実行してみます。

内包表記にすると１行で綺麗にまとまるのですが、内包表記は初心者にはフクザツすぎるため、その説明を超丁寧にやってみます。
ちなみにこの内包表記は前の記事のコメント欄にて教えていただいたものです。


## 環境
- Colaboratory環境
- ブラウザはChrome推奨

## ５行で実行する場合の例
```python:python
! pip install -U mecab-python3 unidic-lite
import MeCab
tagger = MeCab.Tagger()
s = tagger.parse("糠に釘")
print("".join(w.split()[1] for w in s.split("\n") if w.find("\t")>0))
```
「ヌカニグギ」と結果が表示されます。
スクリプトを見て特に疑問がわかない方は以下を読まなくても大丈夫です。

## 丁寧な説明

### まずMeCabを導入します

```python:python
! pip install -U mecab-python3 unidic-lite
import MeCab
```
わかります。

### MeCabで「糠に釘」を形態素解析し、結果を表示してみる

```python:python
tagger = MeCab.Tagger()
s = tagger.parse("糠に釘")
print(s)

# ----結果----
# 糠	ヌカ	ヌカ	糠	名詞-普通名詞-一般			2,0
# に	ニ	ニ	に	助詞-格助詞			
# 釘	クギ	クギ	釘	名詞-普通名詞-一般			0
# EOS
```
わかります。

### 「糠に釘」のヨミガナを表示する

```python:python
print("".join(w.split()[1] for w in s.split("\n") if w.find("\t")>0))

# ----結果----
# ヌカニクギ
```
・・・わかりません。
確かに正しい結果は出ますが、何をやっているのかが全然わかりません。


## 精読作業
ということで、

```
print("".join(w.split()[1] for w in s.split("\n") if w.find("\t")>0))
```
の１行について、内容を一つ一つ丁寧に、徹底的に解読していきます。

まず、分析結果の文字列はsになるので、sの中身をみてみます。

```python:Colab
s
# ----結果----
# '糠\tヌカ\tヌカ\t糠\t名詞-普通名詞-一般\t\t\t2,0\nに\tニ\tニ\tに\t助詞-格助詞\t\t\t\n釘\tクギ\tクギ\t釘\t名詞-普通名詞-一般\t\t\t0\nEOS\n'
```

形態素解析の結果は、データとしては\tの半角スペースと、\nの改行で構成されていることがわかります。

内包表記の処理について、一つずつ見ていきます。

>print("".join(w.split()[1] for w in <b><font color="Red">s.split("\n")</font></b> if w.find("\t")>0))

<font color="Red">s.split("\n")</font>の部分で、先程のsの内容を"\n"を区切り記号として分割しています。
.split("区切り記号")というコマンドは、文字列を"区切り記号"で区切って、それをリストとして格納する処理を行います。
なので<font color="Red">s.split("\n") </font>のこの時点での中身は、

>['糠\tヌカ\tヌカ\t糠\t名詞-普通名詞-一般\t\t\t2,0',
 'に\tニ\tニ\tに\t助詞-格助詞\t\t\t',
 '釘\tクギ\tクギ\t釘\t名詞-普通名詞-一般\t\t\t0',
 'EOS',
 '']

という、ここでは1次元5要素のリスト（配列）となっています。
<font color="GRAY">(そもそもリストがわからないという場合は[こちらの記事](https://qiita.com/Takuya_Fujitani/items/d1c97141e123929d4912)などが参考になります。)</font>

次に、
>print("".join(w.split()[1] <b><font color="BLUE">for w in</font></b> <b><font color="Red">s.split("\n")</font></b> <b><font color="PURPLE">if w.find("\t")>0</font></b>))

を解釈します。
<font color="BLUE">for w in</font>は、<font color="Red">s.split("\n")</font>のリストの中身を変数wに一つずつ代入していく処理です。
<font color="GRAY">(そもそも「for文とリストの組み合わせ」がわからない場合は[こちらの記事](https://ai-inter1.com/python-for/)などが参考になります。)</font>


ただしこの場合、後ろに、<font color="PURPLE">if w.find("\t")>0</font>とあります。
これは、今入ったwを調べ、wに代入された文字列の中に"\t"が1つ以上見つかった場合に限り、w.split()の処理に回すという条件です。

つまり、s.split("\n") の中身について、"\t"を含まない最後の'EOS'と''の要素はここでは処理にされず、排除されることになります。
これで、処理されるものは、
> ['糠\tヌカ\tヌカ\t糠\t名詞-普通名詞-一般\t\t\t2,0',
  'に\tニ\tニ\tに\t助詞-格助詞\t\t\t',
  '釘\tクギ\tクギ\t釘\t名詞-普通名詞-一般\t\t\t0',

の３要素に絞られています。
この３要素、に対して、以下の処理が行われます。

>print("".join(<b><font color="ORANGE">w.split()</font></b>[1] <b>for w in s.split("\n") if w.find("\t")>0</b>))


<font color="ORANGE">w.split()</font>は w.split("\t") と近しい意味で、スペース区切りの配列として単語ごとに配列格納されていきます。

たとえば最初の文字列である
>'糠\tヌカ\tヌカ\t糠\t名詞-普通名詞-一般\t\t\t2,0'

は、この処理によって、
>[ '糠', 'ヌカ', 'ヌカ', '糠', '名詞-普通名詞-一般', '2,0' ]

のように分割され、リストとして格納されます。

ここでなぜ、w.split("\t")ではなく、w.split()とするのでしょうか。
実は.split()は"\t"のような引数を指定しないことで空白全般を分割記号の対象にできる機能を持ちます。
.split()とした場合に分割記号とみなされるのは、具体的には半角スペースに加え、タブ(\t)、改行(\n)、キャリッジリターン(\r)、改ページ(\f)などです。
またこれらが連続した場合には、１スペースとしてひとまとめにした扱いとなるので、結果が安定しやすくなります。

>print("".join(<b><font color="ORANGE">w.split()</font><font color="RED">[1]</font> for w in s.split if w.find("\t")>0</b>))

インデックス指定の<font color="RED">[1]</font>があるので、いま作成されたリストである

[ '糠', <b>'ヌカ'</b>, 'ヌカ', '糠', '名詞-普通名詞-一般', '2,0' ]

について、1番目の要素がピックアップされます。要素は0番から数えるので、ここでは 'ヌカ' が選ばれることになります。

>print(<b><font color="BLUE">"".join</font>(w.split()</font>[1] for w in s.split("\n") if w.find("\t")>0</b>))

その 'ヌカ' が、<font color="BLUE">"".join()</font>として処理されます。
.join()はリストの中の文字列を連結していく処理です。

.join()の書式は、
<font color="BLUE">' 間に挿入する文字列 ' .join ( [ 連結したい文字列のリスト ] )</font>
です。

なので、さきほどピックアップしたデータの各行の1番目にある「読みのカタカナ表記」が、連結され出力されます。

この一連の作業は、
>print("".join(w.split()[1] <b><font color="BLUE">for w in</font></b> <b><font color="Red">s.split("\n")</font></b> if w.find("\t")>0)

の回数だけ繰り返されます。
s.split("\n") の中身は５要素ありますので、５回分文字列の連結が繰り返されます。
（ただし、前述の通り、"\t"を含まない要素は処理をキャンセルされるので、実際に連結されるのは３要素となります。）


## ちなみに

ヨミガナの結果を得るには、fugashiライブラリを使うのが良いようです。
Colab環境でfugashiを使う場合についても、コンパクトにまとめてみました。

- [Colab環境でfugashiを使ってヨミガナを表示する5行]
(https://qiita.com/Ninagawa_Izumi/items/8f582a4f670e406ee0b9)