文字列を複製する - lisp-cookbook-ja/common-lisp GitHub Wiki

文字列 シーケンス

文字列シーケンスなので、複製するにはcopy-seqを利用します。

;; copy-seqはシーケンスを複製する
(copy-seq "foo")        ;=> "foo"

;; barの複製を変更してもbarには影響はない
(let ((foo "fooooo")
      (bar "barrrr"))
  (list (nstring-upcase foo)
        foo
        (nstring-upcase (copy-seq bar))
        bar))
;=> ("FOOOOO" "FOOOOO" "BARRRR" "barrrr")

議論

(concatenate 'string "a")

これでいいんでしょうか。他のイディオムがありますか。

(copy-seq "a")

でどうでしょう

この項目の本題とはずれた議論になりますが、文字列を複製したいと思った理由はキーワードのシンボルネームの型がなんだか普通の文字列と違うようだったからです。複製すれば解決するのかな、と。

(type-of (copy-seq (symbol-name :a)))
; => (SIMPLE-BASE-STRING 1)
(type-of (concatenate 'string (symbol-name :a)))
; => (SIMPLE-ARRAY CHARACTER (1))
(type-of (symbol-name 'a))
; => (SIMPLE-ARRAY CHARACTER (1))

SBCLでしか試していませんが、なぜに返ってくる型が違うんでしょう?--koga

同じだと言えば同じなのかもしれないですけど、 ちなみに CLISP だとどれも(SIMPLE-BASE-STRING 1) になりますね。

なるほど。

(type-of (concatenate 'base-string (symbol-name :a)))
; => (SIMPLE-BASE-STRING 1)
(type-of (symbol-name :あ))
; => (SIMPLE-ARRAY CHARACTER (1))

さらに試してみてなんとなく理解しました。キーワードのシンボルネームについてはおそらくSBCL的により効率のいいbase-string型で管理しているのでしょう。シーケンスの複製なのか型変換も行うのかを意識しなければいけない場面にたまたまでくわしただけ(ライブラリが(SIMPLE-ARRAY CHARACTER (*))型しか受け付けてくれない)だったみたい。--koga

llibra(2011/08/15 04:19:48 PDT): HyperSpecを調べてconcatnateやsubseqについても追加してみました。Schemeよりも副作用を考慮する割合が大きいからか、Common Lispでは明確にアロケーションを要求する関数が多いのが興味深いです。

subseqや、concatenateで新規のシーケンスができる性質を知っておくいうのは良いと思うんですが、専用のcopy-seqがあるのに複製を第一の目的としてsubseqや、concatenateを使うのって難解かなあと思いました。copy-listの代わりにこれらを使ったりはしないですよね。また、concatenateがありだったら(map 'string #'values "foo")、(format nil "foo")、(princ-to-string "foo")もありなのかなあとも。 --g000001

llibra(2011/08/16 07:15:54 PDT): 例えば、subseqやconcatenateを使う関数を定義するときなんかにこの性質を知っていれば、元の文字列と同じ内容の文字列を返す場合でもわざわざcopy-seqしなくても済むよ、という趣旨でした。ただ、言われてみると確かに逆引きリファレンスには蛇足のようにも思えるので、g000001さんの例も加えて、別の場所にまとめてみようかと思います。