我有一个文本文件,每行只有一个句子。我想使用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/

10-14 19:53
查看更多