脳筋プログラミング

筋トレ大好きな初心者プログラマーの備忘録です。

言語処理100本ノック(06〜09)

06.集合

問題:"paraparaparadise"と"paragraph"に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,'se'というbi-gramがXおよびYに含まれるかどうかを調べよ.

和集合,積集合,差集合に関して復習しておきます。 そもそも「集合」とは...

  • 要素が重複しない

  • 要素は順序付けされない

です。これを踏まえたうえで、a・bの2つの集合があった場合、

  • 和集合:aとbどちらかには含まれる

  • 積集合:aとbどちらにも含まれる

  • 差集合:aにのみ含まれる

ということになります。簡単に確認してみます。

a = {1, 1, 2, 4, 5, 7, 8, 9, 0}
b = {2, 3, 5, 5, 6, 9, 0}

x = set(a)
y = set(b)

print('和集合:' + str(x|y))
print('積集合:' + str(x&y))
print('差集合:' + str(x-y))

##########結果##########

和集合:{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
積集合:{0, 9, 2, 5}
差集合:{8, 1, 4, 7}

ということで、問題を解いてみます。

解答:

a = "paraparaparadise"
b = "paragraph"


def text_ngram(x):
    # 文字bi-gram
    text = set([x[b:b+2] for b in range(len(x) - 1)])

    return text

X = text_ngram(a)
Y = text_ngram(b)

wa = str(X|Y)
sa = str(X-Y)
seki = str(X&Y)

print('和集合:' + wa)
print('積集合:' + seki)
print('差集合:' + sa)

if 'se' in X:
    print('Xにseが含まれている')
else:
    print('Xにseが含まれていない')

if 'se' in Y:
    print('Yにseが含まれている')
else:
    print('Yにseが含まれていない')

##########結果##########

和集合:{'di', 'is', 'ad', 'ph', 'ra', 'ag', 'pa', 'ar', 'ap', 'gr', 'se'}
積集合:{'ra', 'ar', 'pa', 'ap'}
差集合:{'di', 'is', 'se', 'ad'}
Xにseが含まれている
Yにseが含まれていない

考察:なし

07.テンプレートによる文生成

問題:引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y="気温", z=22.4として,実行結果を確認せよ.

解答:

def template(x, y, z):
       return print(str(x) + '時の' + str(y) + 'は' + str(z))


template(12, '気温', 22.4)

##########結果##########

12時の気温は22.4

考察:「あれ、全然難しくない」と思いましたが、str()とキャストしているところがイケてない気がします。ということで、fomat関数がありました。忘れてました。(参考:2. 組み込み関数 — Python 3.6.3 ドキュメント

def template(x, y, z):
       return "{0}時の{1}は{2}".format(x, y, z)


print(template(12, '気温', 22.4))

##########結果##########

12時の気温は22.4

08.暗号文

問題:与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ.

  • 英小文字ならば(219 - 文字コード)の文字に置換

  • その他の文字はそのまま出力

この関数を用い,英語のメッセージを暗号化・復号化せよ.

解答:

import re

regex = re.compile('[^a-z]')

def cipher(x):
       return ''.join(re.sub('[a-z]', chr(219-ord(i)), i) for i in x)


text = "Hi! My name is Bob. 20 years old."

print(cipher(text))
print(cipher(cipher(text)))

##########結果##########

Hr! Mb mznv rh Bly. 20 bvzih low.
Hi! My name is Bob. 20 years old.

考察:これも最初は(219 - 文字コード)が理解できないままだった(219文字コードというものが存在するのかと思ってました...)のですが、単純に219から文字コードを引けばいいだけでした。ord関数はUnicodeコードポイントを表す整数を返し、chr関数はその逆をします。(参考:2. 組み込み関数 — Python 3.6.3 ドキュメント

09.Typoglycemia

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

解答:

import random


def randomize(sym):

    str1 = [i for i in sym.split()]

    for y, i in enumerate(str1):
        if len(i) > 4:
            z = []
            for x in i[1:-1]:
                z += x
            random.shuffle(z)
            str1[y] = i[0] + ''.join(z) + i[-1]

    return ' '.join(str1)


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


print(randomize(text))

##########結果##########

I c'oludnt bilevee that I could acultlay unetnrsadd what I was rdaeing : the pnehaneoml pewor of the human mind .
(ランダムなので実行時、都度変わります)

考察:スペースで区切った単語をさらに区切ってシャッフルして...が微妙です。shuffleを利用するためにリスト化していましたが、sampleを使えばリスト化しなくてもいけそうです。(参考:9.6. random — 擬似乱数を生成する — Python 3.6.3 ドキュメント

sampleで書き直したのがこちら

import random


def randomize(sym):

    str1 = [i for i in sym.split()]

    for y, i in enumerate(str1):
        if len(i) > 4:
            str1[y] = i[0] + ''.join(random.sample(i[1:-1], len(i[1:-1]))) + i[-1]

    return ' '.join(str1)


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


print(randomize(text))

##########結果##########

I cl'nudot bleeive that I cloud aullcaty utrdenasnd what I was riendag : the phaoeemnnl pwoer of the haumn mind .
(ランダムなので実行時、都度変わります)

これをさらにリスト内包表記で書くとこんな感じです

import random


def randomize(sym):

    str1 = [i for i in sym.split()]

    str1 = [i[0] + ''.join(random.sample(i[1:-1], len(i[1:-1]))) + i[-1] if len(i) > 4 else i for y, i in enumerate(str1)]

    return ' '.join(str1)


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


print(randomize(text))

##########結果##########

I clun'odt bivleee that I cuold aulaclty unrdsaetnd what I was raiendg : the pnaomhenel pwoer of the hamun mind .
(ランダムなので実行時、都度変わります)

さらに短縮できそうですが、上記の記法でもかなり難読だと思っているので、これぐらいにしておきます。