过滤输出流,只保留特定行数分隔的文本部分?

问题描述 投票:0回答:1

我创建了一个简单的例子来实现我的目标。本质上,我需要运行一个shell命令,并捕获它的输出,但是,只保留其中的特定部分。以下面的bash命令为例。

> echo "hello\nhello\nstart\nI\nWANT\nTHIS\nTEXT\nend\nhello\n"
hello
hello
start
I
WANT
THIS
TEXT
end
hello

我期望的通用语言输出是: (list "I" "WANT" "THIS" "TEXT"). 我有一个半工作的解决方案,但我想知道如何能让我的 确切 所需的输出,以及是否有更习惯的方式来完成这个任务。

首先,我创建一个闭包来跟踪我应该处理的行。

(defun make-pre-processor ()
  (let ((proc-lines nil))
    #'(lambda (str)
        (cond
          ((string= str "start") (setf proc-lines t))
          ((string= str "end") (setf proc-lines nil))
          (proc-lines str)))))

接下来,我使用let语句来启动我的程序,然后循环处理输出流。

(let* ((input (concatenate 'string
                "hello\\n" "hello\\n" "start\\n"
                "I\\n" "WANT\\n" "THIS\\n" "TEXT\\n"
                "end\\n" "hello\\n"))
        (command (concatenate 'string "echo " "\"" input "\""))
        (*proc* (uiop:launch-program command :output :stream))
        (stream (uiop:process-info-output *proc*))
        (take-lines? (make-pre-processor)))
  (uiop:wait-process *proc*)
  (loop while (listen stream) collect
    (funcall take-lines? (read-line stream))))

然后返回

(NIL NIL T "I" "WANT" "THIS" "TEXT" NIL NIL NIL)

如你所见,有 TNIL 我不想要的值。我还必须使用 uiop:wait-process 我不太喜欢,但我想这是必须的。

更广泛的情况是,我有大约100条这样的命令需要运行和解析。所以我将寻求并行运行这些命令。这只是为了一些观点,我将在一个单独的问题中发布。

asynchronous closures lisp common-lisp sbcl
1个回答
3
投票
> (loop for e in '(NIL NIL T "I" "WANT" "THIS" "TEXT" NIL NIL NIL)
        when (stringp e)
        collect e)
("I" "WANT" "THIS" "TEXT")

还有这个。

CL-USER 17 > (defun skip-lines-until (stream stop-line)
               (loop for line = (read-line stream nil)
                     while (and line
                                (not (string= line stop-line)))))
SKIP-LINES-UNTIL

CL-USER 18 > (defun collect-lines-until (stream stop-line)
               (loop for line = (read-line stream nil)
                     while (and line (not (string= line stop-line)))
                     collect line))
COLLECT-LINES-UNTIL

CL-USER 19 > (let ((lines "hi
there
start
1
2
3
stop
more
here"))
               (with-input-from-string (stream lines)
                 (skip-lines-until stream "start")
                 (collect-lines-until stream "stop")))
("1" "2" "3")

2
投票

如果你想在一个地方完成所有的工作,你可以使用... ... loop 来对状态机进行编码。

(with-open-file (in "/tmp/example")
  (loop
    for previous = nil then line
    for line = (read-line in nil nil)
    for start = (equal previous "start")
    for end = (equal line "end")
    for active = nil then (and (not end) (or active start))
    while line
    when active collect line))

这里是一个表格,记录了每一个循环变量在这段时间内的绑定值,为了便于阅读,这里的点表示无。

|----------+-------+-------+-------+------+------|
| line     | hello | start | text  | text | end  |
|----------+-------+-------+-------+------+------|
| previous | .     | hello | start | text | text |
| start    | .     | .     | T     | .    | .    |
| end      | .     | .     | .     | .    | T    |
| active   | .     | .     | T     | T    | .    |
|----------+-------+-------+-------+------+------|
© www.soinside.com 2019 - 2024. All rights reserved.