* [2022-09-10 土]

** common lispでの文字列置換 :lisp:

ネットで検索すると、cookbookだかが出てきて、
cl-ppcreでの置換は出来るように出てる。

またここのサイトなんか見てもやはりcommon-lisp
には標準で文字列の置換がないという指摘がある。

[[https://shammerism.hatenadiary.com/entry/20081203/1297535192][Lispには文字列置換関数がない?]]

中を読むと以下のような関数が定義されてる。

#+BEGIN_SRC lisp
  (defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part 
  is replaced with replacement."
      (with-output-to-string (out)
        (loop with part-length = (length part)
              for old-pos = 0 then (+ pos part-length)
              for pos = (search part string
                                :start2 old-pos
                                :test test)
              do (write-string string out
                               :start old-pos
                               :end (or pos (length string)))
              when pos do (write-string replacement out)
              while pos))) 
#+END_SRC

これに気付かずとりあえず、自分で作ってみた。

#+BEGIN_SRC lisp
  (defun %s (old new obj)
    (let ((old-len (length old)) 
          (start (search old obj))) 
      (concatenate 'string (subseq obj 0 start) new
                   (let ((rest (subseq obj (+ start old-len))))
                     (if (< old-len (length rest))
                         (%s old new rest)
                         rest)))))        ; =>%S 
#+END_SRC

自分なりにppcreとかと時間を比べてみたら
意外とわずかだが速く出来ていた。
向こうは正規表現対応したり内容的にはより
複雑な事やっているからだろうけど。
先程のreplace-allだが定義の仕方
ちょっと素人には厄介な感じはするし、
自分で作った方が感覚的にはわかりやすいかなと。
ただ見ての通り、再帰を使っているから
大きなファイルとかだとちょっと速度がどうなるか?
とも思う。

ついでにcookbookの方のppcreのscanなんてものも
出ていたので、これも置換とほぼ同じ事やってるなと
すぐ作ってみた。

#+BEGIN_SRC lisp
  (defun scan (key obj)
    (let ((key-len (length key))
          (start (search key obj)))
      (values start (+ start key-len))))  ; =>SCAN 
#+END_SRC

車輪の再発明は良くないとは言われるけど、
自分で作ったらアルゴリズムが理解出来るから
無駄ではないと思う。

プログラミングをやっていると一口に言っても
こういうように
プログラムを"使う"人とプログラムを"作る"人
では全然意味や質が違ってくると思う。
多分pythonユーザーの多くは前者じゃないかな?
便利なライブラリがいっぱいあるっていうし。
でも、自分はなんかそういうのがつまらないと
感じてしまう時がある。

だから車輪の再発明なんてもんはどんどんやってもいいと思う。