您的规范有点不完整(例如,什么构成了您的问题中的单词?如果用户添加多个单词怎么办?如果输入为空怎么办?)。下面我使用CL-PPCRE 将输入拆分为不同的单词并一次添加它们,因为它通常看起来很有用。在您的情况下,您可能需要添加更多错误检查。
如果您想与用户交互,您应该读写*QUERY-IO* 流。在这里,我将根据您的要求提供一个带有全局变量的版本,以及另一个没有副作用的版本(除了输入/输出)。
带全局变量
定义全局变量并用一个空的可调数组对其进行初始化。
我使用的是数组,以便在末尾添加单词很容易,但您也可以使用队列。
(defvar *my-words* (make-array 10 :fill-pointer 0 :adjustable t))
以下函数改变全局变量:
(defun side-effect-word-repl ()
(loop
(format *query-io* "~&Please input a word: ")
(finish-output *query-io*)
(let ((words (ppcre:split
'(:greedy-repetition 1 nil :whitespace-char-class)
(read-line *query-io*))))
(dolist (w words)
(when (string-equal w "exit") ; ignore case
(return-from side-effect-word-repl))
(vector-push-extend w *my-words*)))))
无副作用的方法
不鼓励像上面那样使用全局变量。如果您只需要提示 返回一个单词列表,那么以下内容就足够了。在这里,我使用PUSH/NREVERSE 成语来构建生成的单词列表。
(defun pure-word-repl ()
(let ((result '()))
(loop
(format *query-io* "~&Please input a word: ")
(finish-output *query-io*)
(let ((words (ppcre:split
'(:greedy-repetition 1 nil :whitespace-char-class)
(read-line *query-io*))))
(dolist (w words)
(when (string-equal w "exit")
(return-from pure-word-repl (nreverse result)))
(push w result))))))
单词注意事项
正如 jkiiski 评论的那样,在:word-boundary 处拆分单词可能会更好。我尝试了不同的组合,以下结果似乎对奇怪的示例字符串很满意:
(mapcan (lambda (string)
(ppcre:split :word-boundary string))
(ppcre:split
'(:greedy-repetition 1 nil :whitespace-char-class)
"amzldk 'amlzkd d;:azdl azdlk"))
=> ("amzldk" "'" "amlzkd" "d" ";:" "azdl" "azdlk")
我首先删除所有空格并将字符串拆分为字符串列表,其中可以包含标点符号。然后,每个字符串本身在:word-boundary 处拆分,并与MAPCAN 连接以形成单独单词的列表。但是,我无法真正猜测您的实际需求是什么,因此您可能应该定义自己的 SPLIT-INTO-WORDS 函数来验证和拆分输入字符串。