言語処理100本ノック 2020 (Rev 1)を解いてみる(05~09)
完走できるかは怪しい。
WIndows+python 3.8でちょろちょろ解いていく。
05. n-gram
与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ.
以下のone-linerで書ける。 forでのoff-by-oneエラーに気を付けるべし。
def get_ngram(l: list, n: int): return [l[i:i+n] for i in range(len(l)-n+1)] s = "I am an NLPer" print(get_ngram(s.split(" "), 2)) print(get_ngram(s, 2))
06. 集合
“paraparaparadise”と”paragraph”に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,’se’というbi-gramがXおよびYに含まれるかどうかを調べよ.
setを使う。
各種集合に対する操作はsetが標準として持っている。
sx = "paraparaparadise" sy = "paragraph" x = set(get_ngram(sx, 2)) y = set(get_ngram(sy, 2)) print("union:", x.union(y)) print("intersection:", x.intersection(y)) print("diff:", x.difference(y)) search = "se" if search in x: print(search + " is in x") else: print(earch + " isn't in x") if search in y: print(search + " is in y") else: print(search + " isn't in y")
07. テンプレートによる文生成
引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y=”気温”, z=22.4として,実行結果を確認せよ.
pythonの文字列テンプレートは(公式の解説)https://docs.python.org/ja/3/library/string.html#string.Templateで十分わかりやすい。
from string import Template def generate_template_message(x, y, z): s = Template("${X}時の${Y}は${Z}") return s.substitute(X=str(x), Y=str(y), Z=str(z)) print(generate_template_message(12, "気温", 22.4))
08. 暗号文
与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.
- 英小文字ならば(219 - 文字コード)の文字に置換
- その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.
言われた通りのことを実装すれば問題ない。
文字からASCIIコードへの変換はord, ASCIIコードから文字への変換はchrでできる。
cipherを2回実行すると元の文字列に戻ることを確認した。
'''
def cipher(s: str):
return "".join([chr(219-ord(ch)) if ch.islower() else ch for ch in s])
s = "1aA2bB3cC4dD" print(cipher(s)) print(cipher(cipher(s))) '''
09. Typoglycemia
スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ.ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文(例えば”I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .”)を与え,その実行結果を確認せよ.
random.sampleを使う。
random.sampleはstrを受け付けないので、一度リストに変換した。
これなんですが、英語だからか長い英単語はスッと入ってきませんね。
英語が母国語の人は大丈夫なのかな…
''' import random
def mid_shuffle(s: str): if len(s) < 4: return s l = list(s) l[1:-1] = random.sample(l[1:-1], len(l)-2) return "".join(l)
s = "I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind ." print(" ".join([mid_shuffle(word) for word in s.split(" ")])) '''
言語処理100本ノック 2020 (Rev 1)を解いてみる(00~04)
完走できるかは怪しい。
WIndows+python 3.8でちょろちょろ解いていく。
00. 文字列の逆順
文字列”stressed”の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.
pythonで配列を逆順に見るときにはスライシングにおいてステップを-1にすればよい。
print("stressed"[::-1])
01. 「パタトクカシーー」
「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.
二つおきに見るときはスライシングでステップを2にすればよい。
pythonは0-indexedなので注意。
print("パタトクカシー"[::2])
02. 「パトカー」+「タクシー」=「パタトクカシーー」
「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.
pythonだと以下のone-linerでよい(読みやすいかは別として)。
内包表記やzipなどpythonでよく使うがほかの言語ではあまりなさそうな機能を使うので、pythonの練習問題として秀逸。
print("".join(["".join(chs) for chs in zip("パトカー", "タクシー")]))
03. 円周率
“Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.”という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.
以下のone-linerで書けるが、
- 単語への分割はsplit
- 文字数を数えるのはlen
- アルファベットを抜き出すのは正規表現
と考えることは多い。慣れればこのくらいは脊髄反射でできるのだろう、きっと。
import re s = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics." print([len(re.findall("[A-Za-z]", word)) for word in s.split(" ")])
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文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.
特定のインデックスの時だけ処理を分けるのはsetを使えばよい。
s = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can." c1 = set([1, 5, 6, 7, 8, 9, 15, 16, 19]) print(dict([(w[:1], i+1) if i+1 in c1 else (w[:2], i+1) for i, w in enumerate(s.split(" "))]))
英語圏の人はこうやって覚えるのだろうか?
煩雑じゃないですか…