lisp函数用于连接字符串列表

MBU*_*MBU 10 common-lisp string-concatenation

我需要编写一个将列表连接成字符串的函数.示例:

(concatString(quote("hello""world")))==>"hello world"

这是我到目前为止:

(defun concatString (list)
  "A non-recursive function that concatenates a list of strings."
  (cond
   ((not (listp list))
     (princ "Error: argument to concatNR must be a list")(terpri) ())) ; check if parameter is a list

  (if (not (null list)) ;check if list is not null
      (let ((result (car list)))
        (dolist (item (cdr list))
          (if (stringp item)
              (setq result (concatenate result item)))          
        )
      )
  )
)
Run Code Online (Sandbox Code Playgroud)

当我尝试运行它时,我得到一个"错误:"你好"是和非法类型说明符"消息.我已经尝试了很多方法来修改这个功能,但我还没弄清楚.有没有人有任何想法?

Vij*_*hew 16

concatenate需要序列类型说明符作为其第二个参数.要连接两个字符串,您应该调用concatenate:

(concatenate 'string "hello" "world")
Run Code Online (Sandbox Code Playgroud)

代码中的另一个错误:car在分配代码之前,您不确保列表中的字符串是否为字符串result.通过修复代码,我想出了以下实现:

(defun concatString (list)
  "A non-recursive function that concatenates a list of strings."
  (if (listp list)
      (let ((result ""))
        (dolist (item list)
          (if (stringp item)
              (setq result (concatenate 'string result item))))
        result)))

;; tests
> (concatString (list "hello" " world"))
"hello world"
> (concatString (list "hello" 1 2 3 " world"))
"hello world"
> (concatString (list "hello" 1 2 "3" " world"))
"hello3 world"
> (concatString (list 1 2 3 "hello" " world"))
"hello world"
Run Code Online (Sandbox Code Playgroud)

以下重新定义concatString更有效,因为它不会创建许多中间字符串对象:

(defun concatString (list)
  "A non-recursive function that concatenates a list of strings."
  (if (listp list)
      (with-output-to-string (s)
         (dolist (item list)
           (if (stringp item)
             (format s "~a" item))))))
Run Code Online (Sandbox Code Playgroud)


zel*_*lio 15

只需在列表中使用format函数,这会将所有内容转换为字符串,并使用正确的格式字符串将它们连接起来.

(defun my-concat( list )
  (format nil "~{~a~}" list))
Run Code Online (Sandbox Code Playgroud)

如果要将它们与空格连接,请使用带有"〜^"指令的此表单:

(defun my-concat( list )
  (format nil "~{~a~^ ~}" list))
Run Code Online (Sandbox Code Playgroud)

如果您想过滤掉结果,可以在格式化之前转换列表.

(defun my-concat(list)
  (format nil "~{~a~^ ~}" (remove-if-not #'stringp list)))
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用remove-if-not过滤掉非字符串:( defun my-concat(list)(格式为nil"〜{~a~}"(remove-if-not#'stringp list))) (3认同)

Sva*_*nte 8

要将序列连接到字符串,请使用concatenate 'string.

(defun concat-strings (list)
  (apply #'concatenate 'string list))
Run Code Online (Sandbox Code Playgroud)

要从列表中删除非字符串中的任何内容,请使用remove-if-not.

(defun concat-strings (list)
  (apply #'concatenate 'string
         (remove-if-not #'stringp list)))
Run Code Online (Sandbox Code Playgroud)

如果参数不是列表,则会发出错误信号remove-if-not.当然,您可以在添加断言之前提供更具体的错误消息,但这并没有真正增加值.

(defun concat-strings (list)
  (assert (listp list)
          "This is not a list: ~s." list)
  (apply #'concatenate 'string
         (remove-if-not #'stringp list)))
Run Code Online (Sandbox Code Playgroud)

编辑:

正如Rainer所说,apply只适用于有限长度的列表.如果您没有理由相信您的列表不能超过call-arguments-limit-1,那么reduce表单会更好:

(defun concat-strings (list)
  (reduce (lambda (a b)
            (concatenate 'string a b))
          (remove-if-not #'stringp list)))
Run Code Online (Sandbox Code Playgroud)

  • 再看一下,应该注意的是,如果你想连接更多的字符串,那么使用流(例如,`with-output-to-string`)或预先分配结果字符串然后填充更有效.它. (3认同)