use*_*063 1 io common-lisp read-eval-print-loop
我已经学习了Common Lisp一段时间了,有一个问题我遇到过如何实现这样一个函数,允许用户输入一些单词,直到用户输入退出.(实际上我想知道哪种命令行交互功能API符合这样的要求)
例如,在REPL中提示"请输入一个单词:",然后将用户输入存储到全局 my-words中,当用户输入"exit"时退出.
您的规范有点不完整(例如,什么构成您问题中的单词?如果用户添加多个单词怎么办?如果输入为空怎么办?).下面我使用CL-PPCRE将输入分成不同的单词并一次性添加它们,因为它似乎有用.在您的情况下,您可能希望添加更多错误检查.
如果要与用户进行交互,则应该从*QUERY-IO*流中读取和写入流.在这里,我将根据您的要求提供一个带有全局变量的版本,以及另一个没有副作用的版本(除输入/输出外).
定义全局变量并使用空的可调整数组对其进行初始化.我正在使用一个数组,以便在最后添加单词很容易,但你也可以使用一个队列.
(defvar *my-words* (make-array 10 :fill-pointer 0 :adjustable t))
Run Code Online (Sandbox Code Playgroud)
以下函数会改变全局变量:
(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*)))))
Run Code Online (Sandbox Code Playgroud)
在LOOP使用简单的语法那里只有表达式,没有循环特异性的关键字.我先写提示*QUERY-IO*.该~& FORMAT指令执行与之相同的操作FRESH-LINE.正如Rainer在评论中指出的那样,我们必须要求FINISH-OUTPUT确保在用户需要回复之前有效地打印消息.
然后,我从同一个双向流中读取整行,并将其拆分为单词列表,其中一个单词是一个非空白字符串.
有了DOLIST,我迭代列表并用全局数组添加单词VECTOR-PUSH-EXTEND.但是一旦我加密"exit",我就终止了循环; 因为我依赖STRING-EQUAL,测试是不区分大小写的.
不鼓励使用如上所述的全局变量.如果您只需要一个返回单词列表的提示,那么以下就足够了.在这里,我使用PUSH/ NREVERSEidiom来构建结果列表.
(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))))))
Run Code Online (Sandbox Code Playgroud)
正如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")
Run Code Online (Sandbox Code Playgroud)
我首先删除所有空格并将字符串拆分为字符串列表,其中可以包含标点符号.然后,每个字符串本身被拆分:word-boundary,并连接在一起MAPCAN形成一个单独的单词列表.但是,我无法猜测您的实际需求是什么,因此您应该定义自己的SPLIT-INTO-WORDS函数来验证和拆分输入字符串.
| 归档时间: |
|
| 查看次数: |
122 次 |
| 最近记录: |