1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Python未経験者が言語処理100本ノックをやってみる07~09

Last updated at Posted at 2020-03-18

これの続きでーす。
Python未経験者が言語処理100本ノックをやってみる00~04
https://qiita.com/earlgrey914/items/fe1d326880af83d37b22

Python未経験者が言語処理100本ノックをやってみる05~06
https://qiita.com/earlgrey914/items/e772f1b7e5efea114e1d


#07. テンプレートによる文生成
###引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y="気温", z=22.4として,実行結果を確認せよ.

え。なにこれ?
なんか一気にすげー簡単になった・・・?

iinoka.py
x=12
y="気温"
z=22.4

def moziKetsugo(x, y, z):
    print(str(x) + "時の" + y + "" + str(z))

moziKetsugo(x, y, z)
12時の気温は22.4

これでいいのか・・・?あまりにも簡単すぎないか・・・?
ちょっと穿った視点で考えてみよう。
この問題は引数が「x, y, z」という文字列だったら「x時のyはz」と返し、
x=12, y="気温", z=22.4 という変数だったら文字を当てはめて返す
関数を作る問題ではないだろうか・・・?
(だとしたらもう少しわかりやすくそう書いてくれ)
だとしたら・・・Javaだと引数の有無で処理変えられたけど(何ていうのかわすれた)それと同じようなことをしろってことかしら。

ググった。
デフォルト引数なるものがあるらしい。
<参考>
https://note.nkmk.me/python-argument-default/

これでどうだ。

enshu07.py
x=12
y="気温"
z=22.4

def moziKetsugo(x="x", y="y", z="z"):
    print(str(x) + "時の" + y + "" + str(z))

#ただ出力
moziKetsugo()

#引数を指定して出力
moziKetsugo(x, y, z)
x時のyはz
12時の気温は22.4

うーん、ちょっと出題意図がわからないので、もしわかる人がいたら教えて下さい。
流石にこんな簡単なのでいいのか怪しいゾ・・・

#08. 暗号文
###与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.
・英小文字ならば(219 - 文字コード)の文字に置換
・その他の文字はそのまま出力
この関数を用い,英語のメッセージを暗号化・復号化せよ.

(問題文を見出しにしてたけど、見出しの改行のやり方がわからなかったから変な感じになっちゃったゴメンね)

cipherね、ハイハイ・・・ち、ちpはー(TOEIC340)

まぁとりあえず構成を書く。
問題文に例となる平文くらい書いといてほしいわね(プンプン

punpun.py

genbun = "the magic words are squeamish ossifrage To know is to know that you know nothing That is the true meaning of knowledge"

def cipher(s):
    if s == 英小文字:
        (219 - 文字コード)の文字に置換
        return 暗号後の文字列
    else:
        return そのまま出力

#暗号化        
angobun = cipher(genbun))
print(angobun)

#復号化
fukugobun = decryption(genbun)
print(fukugobun)

で、文字コード変換はどうやるのかなっとググる。
てかこれ何にコード変換するの?UTF-8でいいの?UTF-8だと219-文字コードの部分が実装できないよ・・・?

ググっていたら、pythonには**文字のUnicodeコードポイントっていう整数を返してくれる関数ord()**ってのがあるらしい。たぶんコレを使えってことなんだろう。不親切ね!!!(プンプン

試してみる。

tameshi.py
print("a")
print(ord("a"))
a
97

はー、なるほど。a97ですか。
じゃあ文字列は?

moziha.py
print("abc")
print(ord("abc"))
abc
Traceback (most recent call last):
  File "/home/ec2-user/knock/enshu08.py", line 2, in <module>
    print(ord("abc"))
TypeError: ord() expected a character, but string of length 3 found

なるほど。ord()には1文字ずつ渡せと。OK。

まずこのif文を書こう。

if.py
if s == 英小文字:

「python 英小文字 判断」とかでテキトーにググったらソレ用の関数があるらしい。

小文字かどうかを判定(islower)
英数字であることを判定(isalnum)
英字かどうかを判定(isalpha)

<参考URL>
https://hibiki-press.tech/learn_prog/python/isupper-islower/3728#islower

暗号化できたよー

dekitayo.py
genbun = "aBc0"

def cipher(s):
    kaesubun = ""
    
    for i in s:
        #英字かどうか、かつ小文字かどうか判定
        if i.isalpha() and i.islower():
            kaesubun = kaesubun + chr(219-ord(i))
        else:
            kaesubun = kaesubun + i
    return kaesubun

angobun = cipher(genbun)
print(angobun)
zBx0

上で書き忘れたけど文字→Unicodeコードポイントの変換はord()で、その逆はchr()でできるらしい。
そして今フツーにfor i in s:という書き方をしているが、この記法に演習03で気づいたのはデカい。
(個人的褒めポイント。みんな褒めて!!)
**この記法に気づいていなかったら、わざわざstringを1文字ずつ分割して配列に入れて、取り出して処理・・・なんて書き方をしていたかもしれない。**ていうかJava時代はそう書いていた。

次に復号化。これは簡単ね。

yoyu.py
genbun = "aBc0"

#暗号化の関数
def cipher(s):
    kaesubun = ""
    
    for i in s:
        #英字かどうか、かつ小文字かどうか判定
        if i.isalpha() and i.islower():
            kaesubun = kaesubun + chr(219-ord(i))
        else:
            kaesubun = kaesubun + i
    return kaesubun

#復号化の関数
def decryption(s):
    kaesubun = ""
    
    for i in s:
        if i.isalpha() and i.islower():
            kaesubun = kaesubun + chr(219+ord(i))
        else:
            kaesubun = kaesubun + i
    return kaesubun


print("原文")
print(genbun)

angobun = cipher(genbun)
print("暗号文")
print(angobun)

fukugobun = decryption(angobun)
print("復号文")
print(fukugobun)
原文
aBc0
暗号文
zBx0
復号文
ŕBœ0

アルェーーーーーーーーーー!?!?!?

紙で算数してみたら
chr(219+ord(i))じゃなく chr(219-ord(i))でした。
簡単だと思っているところに落とし穴がある。教訓としてください()

てことで完成↓。

enshu08.py
genbun = "aBcDeFghijKLM0123456789"

#暗号化の関数
def cipher(s):
    kaesubun = ""
    
    for i in s:
        #英字かどうか、かつ小文字かどうか判定
        if i.isalpha() and i.islower():
            kaesubun = kaesubun + chr(219-ord(i))
        else:
            kaesubun = kaesubun + i
    return kaesubun

#復号化の関数
def decryption(s):
    kaesubun = ""
    
    for i in s:
        if i.isalpha() and i.islower():
            kaesubun = kaesubun + chr(219-ord(i))
        else:
            kaesubun = kaesubun + i
    return kaesubun


print("原文")
print(genbun)

angobun = cipher(genbun)
print("暗号文")
print(angobun)

fukugobun = decryption(angobun)
print("復号文")
print(fukugobun)
原文
aBcDeFghijKLM0123456789
暗号文
zBxDvFtsrqKLM0123456789
復号文
aBcDeFghijKLM0123456789

次つぎ!!

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

日本語難しい定期。

まずは全体像。

zenta.py
s = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."

#原文を半角スペースで区切ったリストを作る
list = s.split()

kaesubun = []
for i in list:
    if リスト内の文字列の長さが4より大きい:
        先頭と末尾の文字は残しそれ以外の文字の順序をランダムに並び替える
        kaesubun.append(入れ替えた後の文字)
    else:
        #入れ替えずそのまま
        kaesubun.append(i)

うん、そんなに難しくなさそう。
「それ以外の文字の順序をランダムに並び替える」ってのはどうやるのかなっとググった。

ランダムに複数の要素を選択(重複なし): random.sample()

<参考URL>
https://note.nkmk.me/python-random-choice-sample-choices/

なるほど。
ここで初めてrandomを仕様するために標準ライブラリを使うことになるけどいいのかしら?まぁいいか。
randomを試してみる。

rand.py
import random

s = ["a", "b", "c", "d","e"]
print(random.sample(s, 5))
['c', 'e', 'b', 'a', 'd']

うん。いい感じ。5文字がランダムに取得できた。

「先頭と末尾は残し」ってのは演習02でやったのと同じようにスライスを使う。
「2文字目(1)から末尾の一つ前の文字まで(-1)」とも言えるので[1:-1]と

onazi.py
s = ["a", "b", "c", "d", "e"]
print(s[1:-1])
['b', 'c', 'd']

「先頭」と「末尾」も同じくスライス

nokosi.py
s = ["a", "b", "c", "d", "e"]
print(s[0])
print(s[-1])
['a']
['e']

よし。行けそう。

てかやっぱりスライスの記法、ちょっと面倒ね。
s[-1]は「末尾の1文字」なのに
s[1:-1]は「2文字目から末尾の一つ前の文字まで」なんだよ?
ちょっとわかりづらくない?

↓こう書いたほうがいいかもね。(こんな書き方ができるのかは知らん)
「末尾の1文字」
s[-1: : ]
「2文字目から末尾の一つ前の文字まで」
s[1:-1: ]

~20分後~
できました。

enshu09.py
import random

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

#原文を半角スペースで区切ったリストを作る
kugitta_list = s.split()

kaesubun = []

#原文の単語ごとに処理
for ichitango in kugitta_list:
    #単語が4文字より大きいなら
    if len(ichitango) > 4:
        kaesutango = []
        
        #単語を1文字ずつ区切ってリスト化
        ichitango_kugitta_list= list(ichitango)
        
        #先頭と末尾の文字を除いた文字のリストを作る
        sentou_matsubi_nozoita_list = ichitango_kugitta_list[1:-1]
        
        #先頭の文字を「返す単語」リストに入れる
        kaesutango.append(ichitango_kugitta_list[0])
        
        #先頭と末尾の文字を除いた文字のリストからランダムで全文字を取得して「返す単語」リストに入れる
        kaesutango.extend(random.sample(sentou_matsubi_nozoita_list, len(sentou_matsubi_nozoita_list)))
        
        #末尾の文字を「返す単語」リストに入れる
        kaesutango.append(ichitango_kugitta_list[-1])
        
        #返す単語」を「返す文」のリストに入れる
        kaesubun.append(''.join(kaesutango))
    else:
        #入れ替えずそのまま「返す文」のリストに入れる
        kaesubun.append(ichitango)
        
#返す文の配列を文字列に変換して出力(ついでに配列の要素の区切り文字に空白スペースを指定)
print(' '.join(kaesubun))

I c'ulnodt bvlieee that I could altluacy usraetdnnd what I was rdnieag : the paemonnhel pewor of the hmuan mind .

初出の記法は''.join(kaesubun)かな。

1文字ずつに区切った文字列リストを文字列に変換しているよ。
["a", "b", "c"]というリストがあったなら
''.join(リスト)と書くことでabcと出力されるよ。
'あ'.join(リスト)と書くことでaあbあcと出力されるよ。(「あ」が区切り文字となる)

うーん、我ながら良いぞ。

よし!!!これで言語処理第1章の10問がすべて完了しました!!!!

この記事だけで2時間かかりました!!!!!!!!(重要)
第1章にかかった時間は7時間です!!!!!!(重要)

明日からは第2章でーす。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?