lispとrubyとpythonと その2(common lisp) ver2

ちまちまと更新。
common lispは日付まわりが面倒くさいなぁ。
universal-timeが基本になってるのがすでに微妙。
整備されたライブラリが欲しい・・・。

;;文字列連結
;;concatenateで連結
(format t (concatenate 'string "あいう" "えお"))
;;->あいうえお

;;formatで連結
(print (format nil "~A~A" "あいう" "えお"))
;;->"あいうえお" 

;;どちらもめんどい

;;文字列の分割
;;split-sequenceはやめ
;;cl-utilitiesで
;;マニュアルはここ
;;http://common-lisp.net/project/cl-utilities/doc/
;;asdfで入れとくこと
(require 'cl-utilities)
(setf sq0 (cl-utilities:split-sequence #\, "あああ,いいい,ううう,えええ,おおお"))
(mapc #'(lambda (s)
   (format t "~A~%" s ))
      sq0)
;; ->あああ
;;  いいい
;;  ううう
;;  えええ
;;  おおお

(setf sq1 (cl-utilities:split-sequence-if
    #'(lambda (c)
        (or (char= c #\,)
     (char= c #\.)))
    "あああ,いいい.ううう,えええ.おおお"))
(mapc #'(lambda (s)
   (format t "~A~%" s))
      sq1)
;;->あああ
;;  いいい
;;  ううう
;;  えええ
;;  おおお

;;文字列検索
;;cl-ppcreを使う
(require 'cl-interpol)
(cl-interpol:enable-interpol-syntax)
(require 'cl-ppcre)

(if (cl-ppcre:scan #?/かきくけこ/ #?"あいうえおかきくけこさしすせそ")
    (format t "みつかった~%")
    (format t "みつからない~%"))
;;->みつかった

(if (cl-ppcre:scan #?/たちつてと/ #?"あいうえおかきくけこさしすせそ")
    (format t "みつかった~%")
    (format t "みつからない~%"))
;;->みつからない

;;みつかったら開始位置と終了位置が多値で返る
(multiple-value-bind(s e)
    (cl-ppcre:scan #?/かきくけこ/ #?"あいうえおかきくけこさしすせそ")
  (format t "~A ~A~%" s e))
;;->5 10

;;部分文字列の取得
(format t (subseq "あいうえおかきくけこさしすせそ" 5 10))
;;->かきくけこ

;;特定の文字の場所を探して部分文字列取得とかありがちじゃない?
(setf target "あいうえお-かきくけこ")
(multiple-value-bind(s e)
    (cl-ppcre:scan #?/-/ target)
  (if s
      (format t "~A~%" (subseq target 0 s))))
;;->あいうえお

;;文字列比較
;;普通の比較
(if (string= "aaa" "aaa")
    (format t "true~%"))
;;->true

;;case-insensitiveな比較
(if (string-equal "aaa" "AAA")
    (format t "true~%"))
;;->true

;;同値性と同一性
;;比較にはeq、eql、equal、equalpがある
;;eqはポインタの比較
(setf val1 '(a b c))
(setf val2 '(a b c))
(setf alias val1)
(if (eq val1 alias)
    (format t "true~%")
    (format t "false~%"))
;;->true

(if (eq val1 val2)
    (format t "true~%")
    (format t "false~%"))
;;->false

;;eql
;;数値、文字比較。型が一致してeqか同じ値なら真
(if (eql 1 1)
    (format t "true~%")
    (format t "false~%"))
;;->true

(if (eql 1 1.0)
    (format t "true~%")
    (format t "false~%"))
;;->false

;;equal
;;数値、文字列でeqlか型が一致して同じ値なら真
(setf val1 "hello")
(setf val2 "hello")
(if (equal val1 val2)
    (format t "true~%")
    (format t "false~%"))
;;->true

(if (equal 1 1.0)
    (format t "true~%")
    (format t "false~%"))
;;->false

;;equalp
;;数値なら型が違ってもいい
;;文字列なら大文字小文字を気にしない
(if (equalp 1 1.0)
    (format t "true~%")
    (format t "false~%"))
;;->true

(if (equalp "aaa" "AAA")
    (format t "true~%")
    (format t "false~%"))
;;->true

;;数値->文字列変換
(setf ns (format nil "~A" 123.000))
(format t ns)
;;->123.0

(setf ns1 (write-to-string 123.000))
(format t ns1)
;;->123.0

;;文字列->数値変換
(setf sn (parse-integer "123"))
(format t "~A~%" sn)
;;->123

(setf sn1 (read-from-string "123.000"))
(format t "~A~%" sn1)
;;->123.0

;;日付->文字列変換
;;現在日付取得
;;universal-timeは1900年から経過した秒数
(setf dt (get-universal-time))

(multiple-value-bind (s m h dd mm yy)
    (decode-universal-time dt)
  (format t "~A/~A/~A ~A:~A:~A" yy mm dd h m s))
;;->2008/12/14 1:43:6
;;metatilitiesを使ってもオケ
;;asdfでインストールできる
;;でもrequireしたらなーんかコンパイルしてるときに/usr/lib/sbcl/site/...のpermissionエラーになる
;;めんどうだからchmodしちゃった・・・
;;metatilitiesのリファレンスはここ
;;http://common-lisp.net/project/metatilities/documentation/metabang.utilities-package/index.html

;;metatilitiesでuniversal-timeを文字に変えるのはformat-date
;;フォーマットの指定の仕方はここ
;;http://common-lisp.net/project/metatilities/documentation/metabang.utilities-package/function-format--date.html
(require 'metatilities)
(metatilities:format-date "%Y/%m/%d %H:%M:%S" (get-universal-time))
;;->"2008/12/13 23:22:15"

;;ミリ秒単位での取得
;;universal-timeが秒数なのでclの範囲ではとれない
;;システム固有の機能を使う
;;sbcl限定
;;参考っていうかそのまま
;;http://ja.doukaku.org/184/lang/commonlisp/
(defun get-decode-universal-time-with-millisecond()
  (multiple-value-bind (time ms) 
      (sb-unix::system-real-time-values)
    (multiple-value-bind (s mm h d m y)
 (decode-universal-time (+ (encode-universal-time 0 0 0 1 1 1970 0) time))
      (values ms s mm h d m y))))

(multiple-value-bind (ms s mm h d m y)
    (get-decode-universal-time-with-millisecond)
  (format t "~A/~A/~A ~A:~A:~A.~A~%" y m d h mm s ms))
;;->2008/12/13 14:22:28.503

;;文字列をuniversal-timeにする
;;metatilities:parse-date-and-time-stringだとMM/dd/yyyy HH:mm:ssしかparseできない
;;日本には馴染まないからダメ
;;universal-time->文字列->universal-time->文字列
(metatilities:format-date "%Y/%m/%d %H:%M:%S"
     (metatilities:parse-date-and-time-string
      (metatilities:format-date "%m/%d/%Y %H:%M:%S" (get-universal-time)) t))

;;->"2008/12/14 01:23:40"

;;net.telent.date:parse-timeならyyyy/MM/dd HH:mm:ssをuniversal-timeにできる
;;universal-time->文字列->universal-time->文字列
(require 'net-telent-date)
(metatilities:format-date "%Y/%m/%d %H:%M:%S"
     (net.telent.date:parse-time
      (metatilities:format-date "%Y/%m/%d %H:%M:%S" (get-universal-time))))
;;->"2008/12/14 01:27:24"

;;日付、時刻計算
;;universal-timeは1900/1/1 00:00:00からの秒数を持ってるだけだから普通に足し算引き算すればいい
(let ((date1 "2008/12/13 00:00:00")
      (date2 "2008/12/24 00:00:00"))
  (format t "あと~A時間でクリスマスイブ~%" 
   (/ (/ (- (net.telent.date:parse-time date2) (net.telent.date:parse-time date1)) 60) 60)))
;;->あと264時間でクリスマスイブ

;;標準出力に出力
;;;色々ある
(print "hello world")
;;->"hello world~%"
(princ "こんにちは")
;;->こんにちは
;;;formatの第一引数にtを渡すと出力さきは標準出力になる
(format t "こんにちは")
;;->こんにちは

;;標準入力から読み込み
(do ((l (read-line *standard-input*) (read-line *standard-input*)))
    ((string-equal l "exit") 'EXIT)
  (format t "print:~A" l))

;;コマンドライン引数の取得
;;処理系依存らしい。sbclであれば*posix-argv*に入っている
(dolist (arg *posix-argv*)
  (format t "args:~A~%" arg))