在 Common Lisp 中为字符串交替 upcase/downcase
Alternating upcase/downcase for a string in Common Lisp
我想编写一个函数,它将 return 一个用 Common Lisp 中的替代 upcase/downcase 格式化的字符串。例如,输入“Whosebug”应该 return 字符串“Whosebug”。这是我的尝试,但它只是 return 一个缺点对列表。我在正确的轨道上吗?
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil) nil
(coerce (cons
(cons (char-upcase (car lst)) (char-downcase (cadr lst)))
(mockify (cddr lst)))
'string))))
CL-USER> (mockify "meow")
((#\M . #\e) (#\O . #\w))
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil)
;; return nil
nil
;; return a string (coerce)
(coerce
;; a list whose elements are cons-cells, but ...
(cons (cons (char-upcase (car lst))
(char-downcase (cadr lst)))
;; ... the rest is computed by calling mockify,
;; which returns either an empty list or a string
(mockify (cddr lst)))
'string))))
您的表达式类型令人困惑,实际上您的示例在使用 SBCL 时会导致错误:
> (mockify "meow")
The value
(#\O . #\w)
is not of type
CHARACTER
when setting an element of (ARRAY CHARACTER)
[Condition of type TYPE-ERROR]
此外,您将不得不处理代码中的极端情况,因为照原样,可能会在只有一个列表上调用 (cadr list)
,即 (second list)
元素。然后,结果将是 NIL
并且 char-downcase
将失败并出现错误。
仅使用字符串
我建议编写一个不使用中间列表的函数版本:
- 设 R 为整个字符串的
string-downcase
- 然后通过大写来修改 R 的每个其他字符
因此,例如,一种方法(以及其他方法)是:
(defun mockify (chars)
(let ((chars (string-downcase chars)))
(prog1 chars
(upcasify chars 0))))
(defun upcasify (string index)
(when (< index (length string))
(setf (char string index) (char-upcase (char string index)))
(upcasify string (+ index 2))))
仅使用列表
如果您更喜欢处理列表的递归函数,我宁愿分层定义它:
- 强制字符串列表
- 递归处理列表
- 最终,将结果列表强制转换回字符串
这将避免在每一步都进行从字符串到列表的转换,并使每一级的代码更简单。
(defun mockify (chars)
(coerce (mockify-list (coerce chars 'list)) 'string))
(defun mockify-list (chars)
...)
列表版本是递归的,看起来像您尝试做的,但要注意极端情况。
使用 MAP
:我们正在创建一个新字符串,根据交替布尔变量移动原始字符串和 upcase/downcase。
CL-USER 353 > (let ((string "Whosebug")
(upcase t))
(map (type-of string)
(lambda (element)
(prog1 (if upcase
(char-upcase element)
(char-downcase element))
(setf upcase (not upcase))))
string))
"Whosebug"
有不止一种方法可以做到。这是一个基于 loop
的解决方案:
(let ((string "Whosebug"))
(with-output-to-string (s)
(loop :for c :across string
:for up := t :then (not up)
:do (princ (if up
(char-upcase c)
(char-downcase c))
s))))
有趣的东西 - 我前段时间写过类似的东西。
我想编写一个函数,它将 return 一个用 Common Lisp 中的替代 upcase/downcase 格式化的字符串。例如,输入“Whosebug”应该 return 字符串“Whosebug”。这是我的尝试,但它只是 return 一个缺点对列表。我在正确的轨道上吗?
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil) nil
(coerce (cons
(cons (char-upcase (car lst)) (char-downcase (cadr lst)))
(mockify (cddr lst)))
'string))))
CL-USER> (mockify "meow")
((#\M . #\e) (#\O . #\w))
(defun mockify (chars)
(let ((lst (coerce chars 'list)))
(if (equal lst nil)
;; return nil
nil
;; return a string (coerce)
(coerce
;; a list whose elements are cons-cells, but ...
(cons (cons (char-upcase (car lst))
(char-downcase (cadr lst)))
;; ... the rest is computed by calling mockify,
;; which returns either an empty list or a string
(mockify (cddr lst)))
'string))))
您的表达式类型令人困惑,实际上您的示例在使用 SBCL 时会导致错误:
> (mockify "meow")
The value
(#\O . #\w)
is not of type
CHARACTER
when setting an element of (ARRAY CHARACTER)
[Condition of type TYPE-ERROR]
此外,您将不得不处理代码中的极端情况,因为照原样,可能会在只有一个列表上调用 (cadr list)
,即 (second list)
元素。然后,结果将是 NIL
并且 char-downcase
将失败并出现错误。
仅使用字符串
我建议编写一个不使用中间列表的函数版本:
- 设 R 为整个字符串的
string-downcase
- 然后通过大写来修改 R 的每个其他字符
因此,例如,一种方法(以及其他方法)是:
(defun mockify (chars)
(let ((chars (string-downcase chars)))
(prog1 chars
(upcasify chars 0))))
(defun upcasify (string index)
(when (< index (length string))
(setf (char string index) (char-upcase (char string index)))
(upcasify string (+ index 2))))
仅使用列表
如果您更喜欢处理列表的递归函数,我宁愿分层定义它:
- 强制字符串列表
- 递归处理列表
- 最终,将结果列表强制转换回字符串
这将避免在每一步都进行从字符串到列表的转换,并使每一级的代码更简单。
(defun mockify (chars)
(coerce (mockify-list (coerce chars 'list)) 'string))
(defun mockify-list (chars)
...)
列表版本是递归的,看起来像您尝试做的,但要注意极端情况。
使用 MAP
:我们正在创建一个新字符串,根据交替布尔变量移动原始字符串和 upcase/downcase。
CL-USER 353 > (let ((string "Whosebug")
(upcase t))
(map (type-of string)
(lambda (element)
(prog1 (if upcase
(char-upcase element)
(char-downcase element))
(setf upcase (not upcase))))
string))
"Whosebug"
有不止一种方法可以做到。这是一个基于 loop
的解决方案:
(let ((string "Whosebug"))
(with-output-to-string (s)
(loop :for c :across string
:for up := t :then (not up)
:do (princ (if up
(char-upcase c)
(char-downcase c))
s))))
有趣的东西 - 我前段时间写过类似的东西。