如何在SBCL / Common Lisp的过程输入/输出互动(How to interact wi

2019-08-22 17:35发布

我有每行一个句子的文本文件。 我想lemmatize使用中的hunspell(-s选项)每行中的世界。 因为我想单独有各行的引理,那就没有意义提交整个文本文件与hunspell。 我确实需要陆续发送一行,并为每个行中的hunspell输出。

从之后的答案如何处理输入和输出流中钢银行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的每个输入线的输出。

任何的想法?

Answer 1:

我想你有你想要运行的程序的缓冲问题。 例如:

(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-包装的包裹PROGRAMM。



文章来源: How to interact with a process input/output in SBCL/Common Lisp