言語処理100本ノック 2020　第１章

こんにちは。現在、大学院生で自然言語処理の研究をしています。言語処理100本ノックの問題を解いたので、復習がてら載せていこうと思います。

[言語処理100本ノック](https://nlp100.github.io/ja/)


# 第１章：準備運動
## 00.文字列の逆順
問題：文字列”stressed”の文字を逆に（末尾から先頭に向かって）並べた文字列を得よ.
***


```python:python
# 文字列[開始インデックス：終了インデックス：ステップ数]
print("stressed"[::-1])
```
文字列操作の問題ですね。スライスを使うことで逆から文字列を並べて出力します。

## 01.「パタトクカシーー」
問題：「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ．
***
```python:python
# 文字列[開始インデックス：終了インデックス：ステップ数]
print("パタトクカシーー"[::2])
```
ステップ数を変えます。

## 02.「パトカー」＋「タクシー」＝「パタトクカシーー」
問題：「パトカー」＋「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ．
***
```python:python
res = []
#zip関数で複数のリストの要素をまとめて取得
for i,j in zip("パトカー","タクシー"):
   res += i+j
print(''.join(res))
```
joinで文字列を連結して出力します。

## 03.円周率
問題：“Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.”という文を単語に分解し，各単語の（アルファベットの）文字数を先頭から出現順に並べたリストを作成せよ.
***
```python:python
sentence = 'Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.'
# replaceでピリオドを削除
res = [len(i) for i in sentence.replace('.','').split(' ')]
print(res)
```
splitで単語に分割しリスト構造として渡した後に、要素それぞれをfor文で取り出して文字数を取得します。

## 04.元素記号
問題：“Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.”という文を単語に分解し，1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字，それ以外の単語は先頭の2文字を取り出し，取り出した文字列から単語の位置（先頭から何番目の単語か）への連想配列（辞書型もしくはマップ型）を作成せよ．
***
```python:python
sentence ='Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.'

sentence = sentence.replace('.','').split(' ')
res = {}
number = [1,5,6,7,8,9,15,16,19]

for i, word in enumerate(sentence):
    i = i + 1
    if i in number:
        res[word[:1]] = i
    else:
        res[word[:2]] = i
        
print(res)
```
文を単語に分割してから、for文で対応する文字番号のところに数字を格納します。

## 05.n-gram
問題：与えられたシーケンス（文字列やリストなど）からn-gramを作る関数を作成せよ．この関数を用い，”I am an NLPer”という文から単語bi-gram，文字bi-gramを得よ．
***
```python:python
def n_gram(sentence, n):
#スライスを使う
   return [sequence[i:i+n] for i in range(len(sentence-n+1)]
#単語bi-gram
print(n_gram('I am an NLPer',2))
#文字bi-gram
print(n_gram('I am an NLPer'.split(' '), 2))
```
自然言語処理を始める人が最初に聞くn-gramですね。

## 06.集合
問題：“paraparaparadise”と”paragraph”に含まれる文字bi-gramの集合を，それぞれ, XとYとして求め，XとYの和集合，積集合，差集合を求めよ．さらに，’se’というbi-gramがXおよびYに含まれるかどうかを調べよ．
***
```python:python
def n_gram(sentence, n):
   return [sequence[i:i+n] for i in range(len(sentence-n+1)]

X = n_gram('paraparaparadise',2)
Y = n_gram('paragraph', 2)
#set型に直す
X = set(X)
Y = set(Y)
print(X | Y)
print(X & Y)
print(X - Y)
print('se' in X)
```
set型に直すことで、和集合や積集合の計算が簡単にできます。

## 07.テンプレートによる文生成
問題：引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ．さらに，x=12, y=”気温”, z=22.4として，実行結果を確認せよ．
***
```python:python
def output(x,y,z):
  print(f'{x}時の{y}は{z}')

output(12,'気温',22.4)
```
f文字列は文字列リテラルの前にfを置く。文字列中の置換フィールドに変数をそのまま指定できます。

## 08.暗号文
問題：与えられた文字列の各文字を，以下の仕様で変換する関数cipherを実装せよ．

英小文字ならば(219 - 文字コード)の文字に置換
その他の文字はそのまま出力
この関数を用い，英語のメッセージを暗号化・復号化せよ．
***
```python:python
def cipher(xs):
#ordで文字コードに
    xs = [chr(219 - ord(x)) if x.islower() else x for x in xs]
    return ''.join(xs)
```
islowerで小文字かどうかを判定して、暗号化します。

## 09.Typoglycemia
問題：スペースで区切られた単語列に対して，各単語の先頭と末尾の文字は残し，それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ．ただし，長さが４以下の単語は並び替えないこととする．適当な英語の文（例えば”I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .”）を与え，その実行結果を確認せよ．
***
```python:python
import random

def typo(sentence):
    words = sentence.replace('.','').split(' ')
＃間の単語をrandomで混ぜます。
    if len(words) >= 4:
        res = words[0]+ ' ' + ' '.join(random.sample(words[1:-1],len(words)-2)) + words[-1]
    return res

sentence = 'I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .'

print(typo(sentence))
```
ramdom関数で並び替えを行います。