2013-04-13 37 views
5

Tôi có một tệp văn bản với một câu trên mỗi dòng. Tôi muốn lemmatize thế giới trong mỗi dòng bằng cách sử dụng hunspell (-s tùy chọn). Vì tôi muốn có các bổ đề của mỗi dòng một cách riêng biệt, sẽ không có ý nghĩa khi gửi toàn bộ tệp văn bản tới hunspell. Tôi cần phải gửi một dòng khác và có đầu ra hunspell cho mỗi dòng.Cách tương tác với quy trình nhập/xuất trong SBCL/Common Lisp

Làm theo các câu trả lời từ How to process input and output streams in Steel Bank Common Lisp?, tôi đã có thể gửi toàn bộ tệp văn bản cho hunspell một dòng khác nhưng tôi không thể thu được đầu ra của hunspell cho mỗi dòng. Làm thế nào tương tác với quá trình gửi dòng và đọc đầu ra trước khi gửi một dòng khác?

mã hiện tại của tôi để đọc các file văn bản toàn là

(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)))))) 

Một lần nữa, mã này cho tôi đầu ra của hunspell cho các tập tin văn bản nói chung. Tôi muốn có đầu ra của hunspell cho mỗi dòng đầu vào riêng biệt.

Bất kỳ ý tưởng nào?

+0

@wvxvw chắc chắn! Nhưng hunspell có thể được sử dụng tương tác trong dấu nhắc. Nếu tôi bắt đầu nó với "hunspell -s". Đó là lý do tại sao tôi cho rằng tôi có thể làm cho nó hoạt động tương tác với CL. Chắc chắn cách tốt nhất nên được http://common-lisp.net/project/cffi/ nhưng tôi vẫn phải học cách làm việc với nó. –

Trả lời

6

Tôi cho rằng bạn gặp sự cố với chương trình bạn muốn chạy. Ví dụ:

(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))))) 

Bây giờ, trên hệ thống của tôi, điều này sẽ làm việc với 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 

Thông báo các finish-output - không có điều này, đọc sẽ treo. (Ngoài ra còn có force-output.)

Python trong chế độ tương tác sẽ làm việc, quá:

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 

Nhưng nếu bạn cố gắng này mà không có sự -i tùy chọn (hoặc tùy chọn tương tự như -u), có thể bạn sẽ được ra khỏi may mắn, vì bộ đệm đang diễn ra. Ví dụ, trên hệ thống của tôi, đọc từ tr sẽ treo:

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 

Kể từ tr không cung cấp một công tắc để tắt đệm, chúng tôi sẽ quấn cuộc gọi với một wrapper pty (trong trường hợp này unbuffer từ mong đợi):

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 

Vì vậy, câu chuyện dài: Thử sử dụng finish-output trên luồng trước khi đọc. Nếu điều đó không hiệu quả, hãy kiểm tra các tùy chọn dòng lệnh để ngăn đệm. Nếu nó vẫn không hoạt động, bạn có thể thử gói programm trong một số loại pty-wrapper.

+0

Đọc lại câu trả lời của tôi, có lẽ tôi nên làm rõ rằng 'kết thúc đầu ra 'được sử dụng để đảm bảo đầu vào của bạn thực sự được gửi mặc dù đệm - nó không có gì để làm với đầu ra của chương trình. Ngoài ra, các quy trình sẽ không bị đóng khi đóng hai luồng (nhưng đó không phải là vấn đề cho mục đích trình diễn). – danlei

+0

@ Alexandre: Điều đó không giải quyết được vấn đề của bạn? – danlei

+0

Xin cảm ơn, danlei. Câu trả lời của bạn rất có giá trị đối với tôi. – xiepan

Các vấn đề liên quan