Como funciona a read-line em Lisp ao chegar a eof?

Contexto: Tenho um ficheiro de texto chamado fr.txt com 3 colunas de texto nele:

65  A   #\A
97  a   #\a
192     À   #\latin_capital_letter_a_with_grave
224     à   #\latin_small_letter_a_with_grave
etc...

Eu quero criar uma função para ler a primeira coluna (e eventualmente a terceira também) e escrevê-la em outro arquivo de texto chamado alphabet_code.txt.

até agora tenho esta função:

(defun alphabets()
   (setq source (open "fr.txt" :direction :input :if-does-not-exist :error))
   (setq code (open "alphabet_code.txt" :direction :output :if-does-not-exist :create :if-exists :supersede))
   (loop
      (setq ligne (read-line source nil nil))
      (cond
         ((equal ligne nil) (return))
         (t (print (read-from-string ligne) code))
      )
   )
   (close code)
   (close source)
)

Os meus problemas:

  1. não entendo como funcionam os parâmetros da linha de leitura. Li este documento, mas ainda é muito obscuro para mim. Se alguém tivesse exemplos muito simples, isso ajudaria.

  2. com o código atual, eu recebo este erro: *** - read: input stream #<input string-input-stream> has reached its end mesmo que eu mude o nil nil em (read-line source nil nil) para outros valores.

Obrigado pelo seu tempo!

Author: Rainer Joswig, 2017-02-08

1 answers

As suas perguntas

read-line argumentos facultativos

read-line aceita 3 argumentos opcionais:

  1. eof-error-p: o que fazer no EOF (por omissão: erro)
  2. eof-value: o que retornar em vez do erro quando você ver EOF
  3. Estás a ligar-lhe do teu ... print-object método (esqueça isso por agora)

Por exemplo, quando o stream está em EOF,

  • (read-line stream) vai sinalizar o end-of-file erro
  • (read-line stream nil) vai voltar nil
  • (read-line stream nil 42) vai voltar 42.

Note que (read-line stream nil) é o mesmo que (read-line stream nil nil) mas as pessoas geralmente ainda passam o segundo argumento opcional explicitamente. eof-value de nil está bem para read-line porque nil não é uma cadeia de caracteres e read-line só devolve cadeias de caracteres.

Note também que, em caso de read O segundo argumento opcional é, tradicionalmente, o próprio stream: (read stream nil stream). É bastante conveniente.

Erro

Você está recebendo o erro de read-from-string, Não read-line, porque, aparentemente, tens uma linha vazia no teu ficheiro.

Sei disso porque o erro menciona string-input-stream, Não file-stream.

O seu código

O seu código está correcto funcionalmente, mas muito errado estilisticamente.

  1. with-open-file Sempre que possível.
  2. não deve utilizar print em código, é uma estranha função de legado, principalmente para uso interativo.
  3. Você não pode criar variáveis locais com setq - utilização let ou outras formas equivalentes (neste caso, você nunca precisará let! :-)
Eis como eu reescreveria a tua função:
(defun alphabets (input-file output-file)
  (with-open-stream (source input-file)
    (with-open-stream (code output-file :direction :output :if-exists :supersede)
      (loop for line = (read-line source nil nil)
          as num = (parse-integer line :junk-allowed t)
        while line do
          (when num
            (write num :stream code)
            (write-char #\Newline code))))))
(alphabets "fr.txt" "alphabet_code.txt")

Ver os documentos:

  1. loop: for/as, while, do
  2. write, write-char
  3. parse-integer

Em alternativa, em vez de (when num ...) Eu poderia ter usado o correspondente loop condicional .

Também, em vez de write+write-char eu podia ter escrito.

Note que eu não passo os argumentos dewith-open-stream que são idênticos aos valores por omissão. Os valores por omissão são definidos em pedra, e quanto menos código você tem que escrever e seu usuário tem que ler, menos é a chance de erro.

 7
Author: sds, 2017-02-08 13:40:14