あのねノート

せんせいあのね、パソコンで字が書けるようになったよ

言語処理100本ノックを始めました(第1章)

とってもお久しぶりです。研究室に配属されたり試験があったりと忙しくて特に何もしていなかったのですが、夏休みに入ったので研究室の先輩に勧められた言語処理100本ノック 2015を始めることにしました。ふんわり記録を残していこうと思います。なんだかんだでPython3を使っています。

第1章

テキストとか文字列とかを扱うもの。3日前ぐらい?に解きました。準備運動と題されていますがプログラミング久しぶりすぎて慣れるまで大変でした。がんばらないと…

# 00 文字列を逆向きに表示する
# 文字列で向きも指定できるの楽しいって思いました
string = "stressed"

string = string[::-1]
print(string)

# 01 文字列から指定の部分を抜き出して表示する
# 1文字目のことを0と1の間というふうに考えるのがわかりやすくていいなと思いました
string = "パタトクカシーー"

string2 = string[0:1] + string[2:3] + string[4:5] + string[6:7]
print(string2) # パトカー

# 02 2つの文字列を分解して指定の順番につなげる
# forとか使えばもっときれいにいくなあと思いつつ脳筋コードをかきました
# +でそのまま文字列をくっつけられるのが簡単でよいですね
string1 = "パトカー"
string2 = "タクシー"

string = string1[0:1] + string2[0:1] + string1[1:2] + string2[1:2] + string1[2:3] + string2[2:3] + string1[3:4] + string2[3:4] 
print(string) # パタトクカシーー

# 03 単語の文字数をリストにする
# スペースで区切ったあとどうするかなかなか分からずどなたかのコードを参考にしてスペースで区切った後の単語長からコンマとハイフンの数を引くという形をとりました
# スペースで区切ったあと,.を除去したリストを作って数えるのが良かったのかもしれない
string = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
words = string.split(" ")
result = []

for word in words:
	result.append(len(word) - word.count(',') - word.count('.'))

print(result) # [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

# 04 指定された位置の語は最初の1文字、あとは最初の2文字を取り出してインデックスと取り出した文字の辞書を作る
# 元素記号表になるみたいですが12番目のMightだけは合いませんね
# indexと何番目の対応で少し混乱しました(最初が0だったり1だったりとかのありがちなやつ)
string = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."
words = string.split(" ")
indexlist = [1, 5, 6, 7, 8, 9, 15, 16, 19]
resultdict = {}

for word in words:
	if words.index(word)+1 in indexlist:
		resultdict[words.index(word)+1] = word[0:1]
	else:
		resultdict[words.index(word)+1] = word[0:2]

for key, value in resultdict.items():
	print(key, value)

# 05 ngramを作る関数を書き、与えられた文から単語bigramと文字bigramを得る
# 長さとインデックス位置とで混乱したりしました
# スペースの扱いが変わるだけだと思えば同じ関数を使い回せたのかなという気もします
# coding: utf-8

string = "I am an NLPer"

wngram = [] # 単語ngramを格納するリスト
cngram = [] # 文字ngramを格納するリスト

def word_ngram(sequence, n):
	words = []
	words = sequence.split(" ")

	for word in words:
		if len(word) < n: # 単語の長さがnより短ければそのままngramに加える
			wngram.append(word)
		else:
			l = len(word)
			for i in range(0,l-n+1):
				wngram.append(word[i:i+n])

def char_ngram(sequence, n):
	sequence = sequence.replace(' ', '') # スペースを取り除いて1つの文字列につなげる

	if len(sequence) < n:
		cngram.append(sequence)
	else:
		l = len(sequence)
		for i in range(0,l-n+1):
			cngram.append(sequence[i:i+n])

def main():
	word_ngram(string, 2)
	char_ngram(string, 2)

	print("単語ngram")
	for ngram in wngram:
		print(ngram) # I am an NL LP Pe er

	print("文字ngram")
	for ngram in cngram:
		print(ngram) # Ia am ma an nN NL LP Pe er

if __name__ == '__main__':
	main()

# 06 2つの文字列のbigramの集合を求め、和集合、積集合、差集合をとり、それぞれに与えられた文字列"se"が含まれるか確かめる
# 集合の扱いの練習、数学で使う集合と似たような感じで扱えてよかったです
# 順番がバラバラなので一瞬どきっとしたりはしました

# coding: utf-8

string1 = "paraparaparadise"
string2 = "paragraph"

ngram1 = []
ngram2 = []

def char_ngram(sequence, n, ngram): # 05から文字ngramを求める関数を持って来ました
	sequence = sequence.replace(' ', '')

	if len(sequence) < n:
		cngram.append(sequence)
	else:
		l = len(sequence)
		for i in range(0,l-n+1):
			ngram.append(sequence[i:i+n])

def main():
	char_ngram(string1, 2, ngram1)
	char_ngram(string2, 2, ngram2)

	X = set()
	Y = set()

	for ngram in ngram1:
		X.add(ngram)

	for ngram in ngram2:
		Y.add(ngram)

	print("X")
	for ngram in X:
		print(ngram), # ar di ra is se pa ad ap
	print("")

	print("Y")
	for ngram in Y:
		print(ngram), # ap ar ra pa ph ag gr
	print("")

	plusXY = X.union(Y)
	print("X+Y")
	for ngram in plusXY:
		print(ngram), # di ra se ad pa ag gr ar is ph ap
	print("")

	interXY = X.intersection(Y)
	print("X*Y")
	for ngram in interXY:
		print(ngram), # pa ra ar ap
	print("")

	minusXY = X.difference(Y)
	print("X-Y")
	for ngram in minusXY:
		print(ngram), # di ad se is
	print("")

	print("Xにseが含まれる")
	print ("se" in X) # True
	print("Yにseが含まれる")
	print ("se" in Y) # False

if __name__ == '__main__':
	main()

# 07 引数を受け取ってテンプレート文を生成する関数を作る
# 文字列を返すの便利…
# coding: utf-8

def temperature(x, y, z):
	string = x + "時の" + y + "は" + z
	return string

def main():
	temperature("12", "気温", "22.4")
	print(temperature("12", "気温", "22.4")) # 12時の気温は22.4

if __name__ == '__main__':
	main()

# 08 入力文字列が英小文字であれば(219-文字コード)の文字を返し、そうでなければそのまま返す関数cipherと復号関数decipher
# 英小文字の識別、文字→文字コードの変換(とその逆)、いろいろ調べました
# coding: utf-8
def cipher(string):
	clist = list(string) # 入力文字列を文字のリストにする
	rlist = [] # 結果の文字リスト
	for c in clist:
		if c.islower():
			c = chr(219 - ord(c))
			rlist.append(c)
		else:
			rlist.append(c)
	rstr = ''.join(rlist) # 結果文字列
	return rstr

def decipher(string):
	clist = list(string) # 入力文字列を文字のリストにする
	rlist = [] # 結果の文字リスト
	for c in clist:
		ccode = ord(c) # 今の文字コード
		ordcode = 219 - ccode # 元の文字が英小文字だった時の文字コード
		cc = chr(ordcode) # ordcodeを文字に変換したもの
		if cc.islower():
			rlist.append(cc)
		else: # ccが英小文字でなければ元の文字をそのまま
			rlist.append(c)
	rstr = ''.join(rlist) # 結果文字列
	return rstr

def main():
	test = "Python"
	cip = cipher(test)
	print("暗号化:" + cip) # Pbgslm
	decip = decipher(cip)
	print("復号:" + decip) # Python

if __name__ == '__main__':
	main()

# 09 各単語の先頭と最後の文字を残し中の文字列をランダムに並び替えて返す
# ランダムに並び替えるのどうやるんだろうってなりましたがシャッフル関数があるんですね…なんでもあるなあって気持ち
# 文字列→リスト→文字列の操作に慣れました

# coding: utf-8
import random

def typo(string):
	words = string.split(" ")
	rlist = [] # 結果ワードリスト

	for word in words:
		if len(word) < 5:
			rlist.append(word)
		else:
			l = len(word) # 単語の長さ
			randstr = word[1:l-1] # 並べ替え対象文字列を取り出す
			randlist = list(randstr)
			random.shuffle(randlist) # ランダムに並べ替え
			randstr = ''.join(randlist) # 並べ替えしたリストを文字列に戻す
			word = word[:1] + randstr + word[l-1:]
			rlist.append(word)

	rstr = ' '.join(rlist) # 結果文字列をスペース区切りで結合した文字列
	return rstr

def main():
	test = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
	print(test)

	result = typo(test)
	print(result)
        # 例
        # I cd'lonut bvleeie that I cuold atclluay uradesnntd what I was rdaenig : the phoaneenml pwoer of the hmuan mind .

if __name__ == '__main__':
	main()

新しい言語に慣れるという感じでおもしろかったです。