我有一个文本文件,每行只有一个句子。我想使用hunspell(-s选项)对每行中的世界进行定形。由于我想分别设置每行的引理,因此将整个文本文件提交给hunspell毫无意义。我确实需要发送另一行,并且每行都有hunspell输出。
遵循How to process input and output streams in Steel Bank Common Lisp?的回答,我能够逐行发送hunspell的整个文本文件,但是我无法捕获每一行的hunspell的输出。在发送另一行之前,如何与发送行并读取输出的过程进行交互?
我当前读取整个文本文件的代码是
(defun parse-spell-sb (file-in)
(with-open-file (in file-in)
(let ((p (sb-ext:run-program "/opt/local/bin/hunspell" (list "-i" "UTF-8" "-s" "-d" "pt_BR")
:input in :output :stream :wait nil)))
(when p
(unwind-protect
(with-open-stream (o (process-output p))
(loop
:for line := (read-line o nil nil)
:while line
:collect line))
(process-close p))))))
再一次,此代码为我提供了整个文本文件的hunspell输出。我想分别为每条输入线提供hunspell的输出。
任何想法?
最佳答案
我想您要运行的程序存在缓冲问题。例如:
(defun program-stream (program &optional args)
(let ((process (sb-ext:run-program program args
:input :stream
:output :stream
:wait nil
:search t)))
(when process
(make-two-way-stream (sb-ext:process-output process)
(sb-ext:process-input process)))))
现在,在我的系统上,它将与
cat
一起使用:CL-USER> (defparameter *stream* (program-stream "cat"))
*STREAM*
CL-USER> (format *stream* "foo bar baz~%")
NIL
CL-USER> (finish-output *stream*) ; will hang without this
NIL
CL-USER> (read-line *stream*)
"foo bar baz"
NIL
CL-USER> (close *stream*)
T
注意
finish-output
–否则,读取将挂起。 (还有 force-output
。)交互模式下的Python也可以工作:
CL-USER> (defparameter *stream* (program-stream "python" '("-i")))
*STREAM*
CL-USER> (loop while (read-char-no-hang *stream*)) ; skip startup message
NIL
CL-USER> (format *stream* "1+2~%")
NIL
CL-USER> (finish-output *stream*)
NIL
CL-USER> (read-line *stream*)
"3"
NIL
CL-USER> (close *stream*)
T
但是,如果不使用
-i
选项(或类似的选项-u
)尝试此操作,则由于正在进行缓冲,您可能会不走运。例如,在我的系统上,从tr
读取将挂起:CL-USER> (defparameter *stream* (program-stream "tr" '("a-z" "A-Z")))
*STREAM*
CL-USER> (format *stream* "foo bar baz~%")
NIL
CL-USER> (finish-output *stream*)
NIL
CL-USER> (read-line *stream*) ; hangs
; Evaluation aborted on NIL.
CL-USER> (read-char-no-hang *stream*)
NIL
CL-USER> (close *stream*)
T
由于
tr
不提供关闭缓冲的开关,因此我们将使用pty包装器包装该调用(在这种情况下,期望中的unbuffer
):CL-USER> (defparameter *stream* (program-stream "unbuffer"
'("-p" "tr" "a-z" "A-Z")))
*STREAM*
CL-USER> (format *stream* "foo bar baz~%")
NIL
CL-USER> (finish-output *stream*)
NIL
CL-USER> (read-line *stream*)
"FOO BAR BAZ
"
NIL
CL-USER> (close *stream*)
T
因此,长话短说:在阅读之前,请尝试在流上使用
finish-output
。如果那不起作用,请检查防止缓冲的命令行选项。如果仍然不起作用,则可以尝试将程序包装在某种pty包装机中。关于common-lisp - 如何与SBCL/Common Lisp中的过程输入/输出交互,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/15988870/