きょうこログ

初心忘れず、最後まで全力で頑張ります。よろしくお願いします。

言語処理100本ノック【第1章 前編】

課題研究で言語処理100本ノック 2015に取り組んでいます。使用言語はPython3です。文章を書く練習も兼ねてちょっとずつ記録を残していこうと思います。初めは第1章前半の5つです。

作ったプログラムはGitHubに公開しています。指摘等あれば是非よろしくお願いします!

00. 文字列の逆順

文字列"stressed"の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ.

ソースコード

f = reversed(list("stressed"))
a = ''.join(f)
print(a)

list()は、シーケンス型のオブジェクト(順序のある要素の集まり)からリストを作成する関数です。文字列も左から順番に読む要素(アルファベット)の集まりだと考えられるので、list()を用いるとリストとして扱うことが出来ます。reversed()はリストを逆順にする関数です。

これをjoin()を使って文字列に戻し、出力します。

実行結果

desserts

01. 「パタトクカシー」

「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ.

ソースコード

a = "パタトクカシー"[::2]
print(a)

今回はスライスを使いました。スライスとは、シーケンス型のオブジェクトから欲しい要素を抜き出す書き方です。オブジェクトに対して[始まりの位置 : 終わりの位置 : ステップ]を右側に書くことで使えます。始まりの位置を省略すると0、終わりの位置を省略するとオブジェクトの末尾が参照されます。このプログラムでは、始まりの位置 = 0、終わりの位置 = 末尾、ステップ = 2なので、文字列の左端から最後まで順番に1文字飛ばしで要素が抜き出されます。

抜き出した要素はそのまま文字列として合体して返ってくるので、そのまま出力します。

実行結果

パトカー

02. 「パトカー」+「タクシー」=「パタトクカシー」

「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ.

ソースコード

a = list("パトカー")
b = list("タクシー")
c = []

for i, j in zip(a, b):
  c += i + j

c = "".join(c)

print(c)

"パトカー"と"タクシー"をlist()でリストに変換した後、2つのリストの先頭から順番に1つずつ要素を呼び出して合体させていきます。zip()は、2つ以上のリストの各要素をタプルにまとめて返す関数です。zip()を用いるとfor文の最初のループで、i = "パ"、j = "タ"が返ってきます。文字列同士は+演算子を使って連結し、+=演算子を使って別に用意したリストに要素として追加します。

これをjoin()を使って文字列に戻し、出力します。

実行結果

パタトクカシーー

03. 円周率

"Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ.

ソースコード

import re

a = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."

a = re.sub(r'[\.,]+', "", a)
a = a.split()
result = []

for w in a:
  result.append(len(w))

print(result)

この英文には解答に必要のない ", " とか ". " が含まれているので、reモジュールをインポートし正規表現を使って取り除きました。正規表現とは文字列のパターンを照合する表現のことです。例えば[\.,]だと、", " か ". " のどちらかであることを表しています。re.sub()正規表現を使って文字列を置換する関数です。re.sub(正規表現, 置換後の文字列, 置換対象) と記述して使います。このプログラムでは、英文に含まれる ", " や ". " を何も含まない文字列 "" に置換しました。split()は文字列を区切る関数です。引数を省略すると文字列に対してスペース区切りしたものを リストにして返してくれます。

re.sub()split()を使って得られたリストから順番に単語を取り出し、len()を使って文字数を得ます。この文字数をあらかじめ用意した別のリストに要素として追加することで文字数を先頭から出現順に並べたリストが完成します。

実行結果

[3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]

ちなみに得られたリストには、円周率 3.141592... の数字を順番に並べたものが格納されています。

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文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ.

ソースコード

import re

a = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."

pull = [1, 5, 6, 7, 8, 9, 15, 16, 19]

a = re.sub(r'[\.,]+', "", a)
a = a.split()
result = {}

for i in range(len(a)):
  if i + 1 in pull:
    result[i + 1] = a[i][:1]
  else:
    result[i + 1] = a[i][:2]

print(result)

range()は連番のリストを作る関数です。range()を使って得たインデックスがリストpullに含まれるかを判別して、取り出す文字数を決定します。先頭文字の取得に始まりの位置 = 0、終わりの位置 = 1または2、ステップ = 1のスライスを使っています。

取得したインデックスと先頭文字を格納する為の連想配列には辞書を使用しました。辞書名[辞書のkey] = 辞書の値で辞書にデータを登録出来ます。

実行結果

{1: 'H', 2: 'He', 3: 'Li', 4: 'Be', 5: 'B', 6: 'C', 7: 'N', 8: 'O', 9: 'F', 10: 'Ne', 11: 'Na', 12: 'Mi', 13: 'Al', 14: 'Si', 15: 'P', 16: 'S', 17: 'Cl', 18: 'Ar', 19: 'K', 20: 'Ca'}

もちろん完全無欠のコードじゃないです。 指摘頂いた所も追記していければと思います!