Gaucheで言語処理100本ノック2015 第1章: 準備運動

lisp初心者がGaucheで言語処理100本ノックに挑戦

# 第1章: 準備運動
## 00. 文字列の逆順
文字列"stressed"の文字を逆に（末尾から先頭に向かって）並べた文字列を得よ．

```scm
(list->string
  (reverse
    (string->list "stressed")))
```

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

```scm
(let* ((xs (string->list "パタトクカシーー"))
       (ys (iota (length xs)))
       (zs (map cons xs ys)))
  (list->string
    (map car
      (filter (lambda (z) (even? (cdr z))) zs))))
```

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

```scm
(let ((xs (string->list "パトカー"))
      (ys (string->list "タクシー")))
  (string-join
    (map list->string
      (map list xs ys))
    ""))
```

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

```scm
(use srfi-13)

(define s "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.")

(map
  (lambda (x) (string-length (string-filter #[\w] x)))
  (string-split s #[\s+]))
```

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

```scm
(use gauche.sequence)

(define xs "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can.")
(define ys '(1 5 6 7 8 9 15 16 19))

(map-with-index
  (lambda (i x) (if (member (+ i 1) ys)
                    (substring x 0 1)
                    (substring x 0 2)))
  (string-split xs " "))
```

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

```scm
(use gauche.sequence)

(define (sequence-length xs)
  (fold (lambda (x acc) (+ acc 1))
        0
        xs))

(define (ngram n seq)
  (map-with-index
    (lambda (i x) (if (< (+ i n) (sequence-length seq))
                      (subseq seq i (+ i n))
                      (subseq seq i)))
    seq))

(define s "I am an NLPer")
(ngram 2 (string-split s " "))
(ngram 2 (string-filter #[\w] s))
```

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

```scm
(define xs (ngram 2 "paraparaparadise"))
(define ys (ngram 2 "paragraph"))

(use srfi-1)

(lset-union equal? xs ys)
(lset-intersection equal? xs ys)
(lset-difference equal? xs ys)
(member "se" xs)
(member "se" ys)
```

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

```scm
(define (template x y z)
  (format "~a時の~aは~a" x y z))

(template 12 "気温" 22.4)
```

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

```scm
(define (cipher s)
  (list->string
    (map (lambda (x) (if (char-lower-case? x)
                     (integer->char (- 219 (char->integer x)))
                     x))
         s)))

(cipher "Gauche is an R7RS Scheme implementation.")
(cipher (cipher "Gauche is an R7RS Scheme implementation."))
```

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

```scm
(use gauche.sequence)

(define (typoglycemia x)
  (string-join
    (map (lambda (y) (let ((n (string-length y)))
                     (if (>= n 4)
                         (string-append (substring y 0 1)
                                        (shuffle (substring y 1 (- n 1)))
                                        (substring y (- n 1) n))
                         y)))
         (string-split x " "))
    " "))

(typoglycemia "I couldn't believe that I could actually understand what I was reading : the phenomenal power of the human mind .")
```