なんじゃくにっき

プログラミングの話題中心。

言語処理100本ノック を解いてみる

言語処理100本ノックを解いていきます。

言語処理100本ノック 2020 (Rev 2) - NLP100 2020

解くのに使ったプログラミング言語Python 3。

なるべく関数型言語チックに書いているつもりです。再代入はなるたけ避ける。

解答はgithubにも載せておきます。

GitHub - nanjakkun/nlp_100_ans: 言語処理100本ノックの解答

1章の答えと解説だけこの記事にも載せます。

全部解説書こうと思ったけど力尽きたのでgithub見てください・・

(3/24現在 40問まで終了)

1章 準備運動の解答

00

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

str = "stressed"[::-1]
print(str)

sliceの使い方を知っていれば一瞬。[start:stop:step]。

他言語から来るとstrにreverseってメソッドが欲しくなるかも。

01

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

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

これも前問と同様sliceの使い方知ってれば。

02

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

itr = map(lambda x: x[0] + x[1], zip("パトカー", "タクシー"))
print("".join(itr))

zip使いましょう。

03

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

import re

str1 = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics."
itr1 = map(lambda str: len(str), re.split(r'[\s,\.]+', str1))
itr2 = filter(lambda x: x > 0, itr1)
print(list(itr2))

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

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

def to_elemnt_symbol(itr) -> str:
  idx = itr[0]
  if (idx in [1, 5, 6, 7, 8, 9, 15, 16, 19]):
    return itr[1][0], idx
  else:
    return itr[1][0:2], idx

itr1 = filter(lambda x: len(x) > 0, re.split(r'[\s,\.]+', str1))
itr2 = map(to_elemnt_symbol, enumerate(itr1, 1))

print(dict(itr2))

他言語だとmapWithIndexみたいなのを使うところはPythonではenumerate。

05

与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ. この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ.

def word_n_gram(text, num=2):
  words = text.split(" ")
  return list(map(lambda i: words[i:i+num], range(len(words))))

def char_n_gram(text, num=2):
  words = text.replace(" ", "")
  return list(map(lambda i: words[i:i+num], range(len(words))))

text1 = "I am an NLPer"

print(word_n_gram(text1, 2))
print(char_n_gram(text1, 2))

06

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

# 前回の問題で使ったのと同じ関数
def char_n_gram(text, num=2):
  words = text.replace(" ", "")
  return list(map(lambda i: words[i:i+num], range(len(words))))

text1 = "paraparaparadise"
text2 = "paragraph"

X = set(char_n_gram(text1))
Y = set(char_n_gram(text2))

print("union: ", X | Y)
print("intersect: ", X & Y)
print("diff: ", X - Y)

if "se" in X:
  print("X contains se")

if "se" in Y:
  print("Y contains se")

Set使いましょう。

07

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

def weather(x: int, y: str, z: float) -> str:
  return f'{x}時の{y}は{z}'

print(weather(12, "気温", 22.4))

文字列に変数展開する方法はいくつかあるけどその1つ。

08

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

def cipher(text: str) -> str:
  def transform_char(ch):
    if (97 < ord(ch) & ord(ch) < 122):
      return chr(219 - ord(ch))
    else:
      return ch

  return "".join(list(map(transform_char, text)))

text1 = "lorem ipsum"
print(cipher(text1))
print(cipher(cipher(text1)))

decodeとencodeが同じ関数なんですねえ。2回同じのを作用させると元に戻る。

09

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

import random

def typoglycemia(text) -> str:
  def shuffle(word) -> str:
    if (len(word) <= 4):
      return word
    else:
      substr = word[1:-1:]
      return word[0] + "".join(random.sample(substr, len(substr))) + word[-1]

  words = text.split(" ")
  return " ".join(map(shuffle, words))

text1 = "I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
print(typoglycemia(text1))

以前流行ったアレですね。

この ぶんょしう は イリギス の ケブンッリジ だがいく の けゅきんう の けっか 、 にんんげ は もじ を にしんき する とき その さしいょ と さいご の もさじえ あいてっれば じばんゅん は めくちちゃゃ でも ちんゃと よめる という けゅきんう に もづいとて わざと もじの じんばゅん を いかれえて あまりす。

余談

ChatGPT(3.5)に解けるのかと思って問題を与えてみたら、大体解けますね。ちょっと間違ってたりするけど。

と言ってもこれは解答をネットにアップしている人は他にもいるので、まあ、って感じではありますが。

速度的には自分で書くより向こうのほうがずっと速いのでこちらの完敗でございます。