5

我有一个文本文件,每行一个句子。我想使用 hunspell(-s 选项)对每一行中的世界进行词形还原。由于我想分别拥有每一行的引理,将整个文本文件提交给 hunspell 是没有意义的。我确实需要一行接一行地发送每一行的 hunspell 输出。

遵循如何在 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 。

任何想法?

4

1 回答 1

7

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

(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)的情况下尝试此操作,您可能会因为正在缓冲而倒霉。例如,在我的系统上,读取 fromtr将挂起:

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-wrapper 中。

于 2013-04-14T00:33:19.907 回答