2013-04-13 5 views
5

Ich habe eine Textdatei mit einem Satz pro Zeile. Ich möchte die Welten in jeder Zeile mit hunspell (-s Option) lemmatisieren. Da ich die Lemmas jeder Zeile getrennt haben möchte, wäre es nicht sinnvoll, die gesamte Textdatei an hunspell zu senden. Ich muss eine Zeile nach der anderen senden und die Hunspell-Ausgabe für jede Zeile haben.Wie man mit einer Prozesseingabe/-ausgabe in SBCL/Common Lisp arbeitet

Den Antworten von How to process input and output streams in Steel Bank Common Lisp? folgend, konnte ich die ganze Textdatei für hunspell eine Zeile nach der anderen senden, aber ich war nicht in der Lage, die Ausgabe von hunspell für jede Zeile zu erfassen. Wie interagieren Sie mit dem Prozess Senden der Zeile und Lesen der Ausgabe vor dem Senden einer anderen Zeile?

Mein aktueller Code die gesamte Textdatei ist

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

Noch einmal, dieser Code zu lesen, geben Sie mir die Ausgabe von hunspell für die gesamte Textdatei. Ich möchte die Ausgabe von Hunspell für jede Eingabezeile getrennt haben.

Irgendeine Idee?

+0

@wvxvw sicher! Aber hunspell kann interaktiv in der Eingabeaufforderung verwendet werden. Wenn ich es mit "hunspell -s" beginne. Deshalb habe ich angenommen, dass ich es interaktiv mit CL machen kann. Sicher sollte der beste Weg http://common-lisp.net/project/cffi/ sein, aber ich muss immer noch lernen, damit zu arbeiten. –

Antwort

6

Ich nehme an, Sie haben ein Pufferungsproblem mit dem Programm, das Sie ausführen möchten. Zum Beispiel:

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

nun auf meinem System, wird dies mit cat arbeiten:

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 

Beachten Sie die finish-output - ohne dass dies, wird die Lese hängen. (Es gibt auch force-output.)

Python im interaktiven Modus funktioniert auch:

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 

Aber wenn Sie versuchen, diese ohne die -i Option (oder ähnliche Optionen wie -u), werden Sie wahrscheinlich aus Glück, wegen der Pufferung. Zum Beispiel auf meinem System, von tr Lese hängen werden:

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 

Da tr keinen Switch nicht bieten Pufferung auszuschalten, werden wir das Gespräch mit einem pty Wrapper wickeln (in diesem Fall unbuffer von erwarten):

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 

So lange Geschichte kurz: Versuchen finish-output auf dem Strom unter Verwendung von vor dem Lesen. Wenn dies nicht funktioniert, überprüfen Sie, ob Befehlszeilenoptionen die Pufferung verhindern. Wenn es immer noch nicht funktioniert, könnten Sie versuchen, das Programm in eine Art Pty-Wrapper zu verpacken.

+0

Meine Antwort noch einmal durchlesen, vielleicht sollte ich klarstellen, dass 'finish-output' verwendet wird, um sicherzustellen, dass Ihre Eingabe trotz Pufferung tatsächlich gesendet wird - es hat nichts mit der Ausgabe des Programms an sich zu tun. Außerdem werden die Prozesse beim Schließen der Zweiwege-Streams nicht geschlossen (dies ist jedoch für Demonstrationszwecke kein Problem). – danlei

+0

@Alexandre: Hat das dein Problem nicht gelöst? – danlei

+0

Danke, danlei. Ihre Antwort ist sehr wertvoll für mich. – xiepan

Verwandte Themen