我需要编写一个将列表连接成字符串的函数。例如:
(concatString(quote(“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)))
)
)
)
)
当我尝试运行它时,我收到“错误:”hello“is and illegal type specifier”消息。我已经尝试了很多方法来修改这个功能,但我还没弄清楚。有没有人有任何想法?
答案 0 :(得分:16)
只需在列表中使用format函数,这会将所有内容转换为字符串,并使用正确的格式字符串将它们连接起来。
(defun my-concat( list )
(format nil "~{~a~}" list))
如果要将它们与空格连接,请使用带有“〜^”指令的表单:
(defun my-concat( list )
(format nil "~{~a~^ ~}" list))
如果您想过滤掉结果,可以在格式化之前转换列表。
(defun my-concat(list)
(format nil "~{~a~^ ~}" (remove-if-not #'stringp list)))
答案 1 :(得分:16)
concatenate
需要序列类型说明符作为其第二个参数。要连接两个字符串,您应该将concatenate
称为:
(concatenate 'string "hello" "world")
您的代码中的另一个错误:在将其分配给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"
以下对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))))))
答案 2 :(得分:7)
要将序列连接到字符串,请使用concatenate 'string
。
(defun concat-strings (list)
(apply #'concatenate 'string list))
要从列表中删除非字符串中的任何内容,请使用remove-if-not
。
(defun concat-strings (list)
(apply #'concatenate 'string
(remove-if-not #'stringp list)))
如果参数不是列表,则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)))
编辑:
正如Rainer所说,apply
仅适用于有限长度的列表。如果您没有理由相信您的列表不能超过call-arguments-limit
减去1,那么reduce
表单会更好:
(defun concat-strings (list)
(reduce (lambda (a b)
(concatenate 'string a b))
(remove-if-not #'stringp list)))
答案 3 :(得分:3)
答案 4 :(得分:3)
(concatenate 'string "Karl" " " "Marx")
"Karl Marx"
答案 5 :(得分:2)
为什么要限制自己的名单?
(defun concatenate-strings (sequence)
(reduce #'(lambda (current next)
(if (stringp next)
(concatenate 'string current next)
current))
sequence
:initial-value ""))
答案 6 :(得分:2)
这是我的两分钱:
(defmacro concatString(& rest strings)`(concatenate' string ,@ strings))