読者です 読者をやめる 読者になる 読者になる

'(you lisp me)

Lispって何だ

Lispで日本語を宇宙人言葉にする

Twitterでふざけてこんなツイートをしてみたところ、 '(元ネタ :もののけ姫)

こんな煽りを受けまして、

qiita.com

GroovyよりLispの方が圧倒的にイケメン言語に決まってる(過激派)。
これは対抗しないわけにはいかない。

しかしCommon Lispには良い感じの形態素解析器が無い…
MeCabか何かのバインディングを書いてもいいけれどそれは面倒くさい。
なので以下を参考にしてYahoo! JAPANの日本語形態素解析APIを利用しました。

read-eval-print.blogspot.jp

以下コード。

(eval-when (:compile-toplevel :load-toplevel :execute)
  (require 'asdf)
  (require 'dexador)     ; WebAPIを叩くために利用
  (require 'cxml)        ; XMLをS式に変換するために利用
  (require 'alexandria)) ; リストをシャッフルするために利用

(defparameter *yahoo-appid* "Yahoo AppIDを入れてください")
(defparameter *parse-url* "http://jlp.yahooapis.jp/MAService/V1/parse")

(defun request-parse (text)
  "Yahoo! JAPANの日本語形態素解析APIで、引数で与えられた文字列を形態素に分割し、結果をXML文字列で返します。"
  (dex:post *parse-url*
    :content `(("appid" . ,*yahoo-appid*)
               ;("filter" . "1|2|9|10")
               ("sentence" . ,text))))

(defun parse (text)
  "形態素解析APIの結果XML文字列から(読み . 品詞名)のリストを生成して返します。"
  (destructuring-bind (_a _b (_c _d _e _f word-list))
    (cxml:parse (request-parse text) (cxml-xmls:make-xmls-builder))
    (declare (ignorable _a _b _c _d _e _f))
      (loop for (_a _b (_c _d _e) (_f _g reading) (_h _i pos)) in (cddr word-list)
        collect (cons reading pos))))

(defun kanap (c)
  "引数で与えられた文字がひらがなかどうかを判定します。"
  (< #x3040 (char-code c) #x309f))

(defun htok (c)
  "引数で与えられた文字がひらがなであればカタカナに変換して返します。
   そうでなければそのまま返します。"
  (if (kanap c)
    (code-char (+ (char-code c)
                  #.(- (char-code #\ア)
                       (char-code #\あ))))
    c))

(defun hira->kata (text)
  "引数で与えられた文字列のひらがなをカタカナに変換して返します。"
  (map 'string #'htok text))

(defun leave-pos (wlist)
  "(読み . 品詞名)のリストから特定の品詞以外を取り除き、読みのリストを返します。"
  (loop for w in wlist
        for pos = (cdr w) then (cdr w)
        if (or (string= "名詞" pos)
               (string= "動詞" pos)
               (string= "形容詞" pos)
               (string= "形容動詞" pos)
               (string= "副詞" pos)
               (string= "接続詞" pos))
        collect (car w)))

(defun ->alien (text)
  "与えられた文字列を宇宙人言葉に変換して返します。"
  (format nil "~{~A~^ ~}"
    (alexandria:shuffle (mapcar #'hira->kata
                                (leave-pos (parse text))))))

(->alien "プログラミング言語Common Lispは最高にクールです。")

API実行部分を除けばおよそ30行程度で、とても短いですね!
そして特殊な構文も少なくて分かり易い!

実行結果はランダムなのですが、今回は以下のようになりました。

"プログラミング クール ゲンゴ Common Lisp サイコウ"

なんて物分かりの良い宇宙人なのでしょうか。
宇宙人もCommon Lispを使っているのかも(?)

さらに走れメロスの冒頭でも試してみます。

(dolist (s '("メロスは激怒した。"
             "必ず、かの邪智暴虐の王を除かなければならぬと決意した。"
             "メロスには政治がわからぬ。"
             "メロスは、村の牧人である。"
             "笛を吹き、羊と遊んで暮して来た。"
             "けれども邪悪に対しては、人一倍に敏感であった。"))
  (format t "~A~%" (->alien s)))

以下結果です。

メロス ゲキド
カナラズ ケツイ ノゾカ ジャチ ボウギャク オウ
セイジ メロス ワカラ
メロス ムラ ボクジン
フエ フキ クラシ アソン ヒツジ キ
タイシ ビンカン ジャアク ヒトイチバイ ケレドモ

動詞を原形に戻す処理を行っていないのでなんとなくヘンテコな感じになってしまいましたが、それらしくはなったと思います。
それはともかくとして、やっぱりCommon Lisp サイコウ クール プログラミング ゲンゴ
Common Lispはこれからも現役です。

ネタをくださいました@saba1024さんに感謝いたします:)