Ruby で 言語処理100本ノック 2015 第1章

# はじめに

- Ruby で [言語処理100本ノック](http://www.cl.ecei.tohoku.ac.jp/nlp100/)の第1章をやってみた



# 回答
## 00. 文字列の逆順
文字列"stressed"の文字を逆に（末尾から先頭に向かって）並べた文字列を得よ．

```ruby
"stressed".reverse
#=> "desserts"
```

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

```ruby
"パタトクカシーー".chars.select.with_index { |char, i| i.even? }.join
#=> "パトカー"
```

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

```ruby
"パトカー".chars.zip("タクシー".chars).join
#=> "パタトクカシーー"
```

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

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

str.split(/\W/).reject(&:empty?).map(&:length)
=> [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9]
```

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

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

str.split(/\W/).reject(&:empty?).map.with_index(1) do |str, i|
  if [1, 5, 6, 7, 8, 9, 15, 16, 19].include?(i)
    [str.slice(0, 1), i]
  else
    [str.slice(0, 2), i]
  end
end.to_h

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

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

```ruby
def n_gram(sequence, n)
  sequence.each_cons(n).map(&:join)
end

chars = "I am an NLPer".chars.reject { |c| c == ' ' }
n_gram(chars, 2)
# => ["Ia", "am", "ma", "an", "nN", "NL", "LP", "Pe", "er"]

words = "I am an NLPer".split
n_gram(words, 2)
# => ["Iam", "aman", "anNLPer"]
```

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

```ruby
x = n_gram("paraparaparadise".chars, 2)
y = n_gram("paragraph".chars, 2)

# 和集合
x | y
#=> ["pa", "ar", "ra", "ap", "ad", "di", "is", "se", "ag", "gr", "ph"]

# 積集合
x & y
#=> ["pa", "ar", "ra", "ap"]

# 差集合
x - y
#=> ["ad", "di", "is", "se"]

x.include?("se")
#=> true

y.include?("se")
#=> false
```

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

```ruby
def template_string(x, y, z)
  "#{x}時の#{y}は#{z}"
end

template_string(12, "気温", 22.4)
#=> "12時の気温は22.4"
```

## 08. 暗号文
与えられた文字列の各文字を，以下の仕様で変換する関数cipherを実装せよ．

- 英小文字ならば(219 - 文字コード)の文字に置換
- その他の文字はそのまま出力

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

```ruby
def cipher(plain_text)
  plain_text.chars.map { |c| c.match?(/[a-z]/) ? (219 - c.ord).chr : c }.join
end

cipher("I am an NLPer")
#=> "I zn zm NLPvi"

cipher("I zn zm NLPvi")
#=> "I am an NLPer"
```

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

```ruby
class String
  def typoglycemia
    return self if self.length <= 4
    self.chars[1..-2].shuffle.unshift(chars.first).push(chars.last).join
  end
end

str = "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind ."
str.split.map(&:typoglycemia).join(' ')
#=> "I cndo'ult bveliee that I cloud alctualy usatnedrnd what I was reiadng : the phnnaeomel pewor of the hmuan mind ."
```