Чтение массива из текстового файла в Common Lisp - PullRequest
3 голосов
/ 02 февраля 2012

Я пытаюсь прочитать данные (которые на самом деле массив) в Лисп из текстового файла.Я пытался использовать with-open-file и read-line, но не смог достичь своей цели.То, что я ищу, эквивалентно выполнению data=load('filename.txt') в MATLAB, поэтому я получаю массив с именем data, который загрузил всю информацию в filename.txt.

Текстовый файл будет в форматекак

1.0 2.0 3.0 ...
1.5 2.5 3.5 ...
2.0 3.0 4.0 ...
 .....

Размер также может варьироваться.Заранее большое спасибо.

Ответы [ 4 ]

4 голосов
/ 05 февраля 2012

Основной способ сделать это - использовать with-open-file для получения входного потока, read-line в loop для получения строк, split-sequence (из библиотеки с тем же именем), чтобы разбить его на поля и parse-number (из одноименной библиотеки) для преобразования строк в числа. Все упомянутые библиотеки доступны с Quicklisp .

РЕДАКТИРОВАТЬ: просто, чтобы начать, это простая версия без проверки:

(defun load-array-from-file (filename)
  (with-open-file (in filename
                      :direction :input)
    (let* ((data-lol (loop :for line := (read-line in nil)
                           :while line
                           :collect (mapcar #'parse-number:parse-number
                                            (cl-ppcre:split "\\s+" line))))
           (rows (length data-lol))
           (columns (length (first data-lol))))
      (make-array (list rows columns)
                  :initial-contents data-lol))))

Вам следует добавить несколько проверок и подумать о том, что вы хотите получить в случае, если они не выполнены:

  • Все ли строки одинаковой длины?
  • Являются ли все поля действительными числами?
4 голосов
/ 02 февраля 2012

Если ваш файл соответствует шаблону форматирования, который вы задали в своем вопросе: последовательность чисел, разделенных пробелами, это быстрый фрагмент кода, который должен делать то, что вы хотите.

(defun read-array (filename)
  (with-open-file (in filename)
    (loop for num = (read in nil)
          until (null num)
          collect num)))
2 голосов
/ 15 февраля 2012

Я последовал совету Сванте.Мне просто нужен был один столбец в текстовом файле, именно это я и использую для этой цели.

(defun load_data (arr column filename)
(setf lnt (first (array-dimensions arr)))
 (with-open-file (str (format nil "~A.txt" filename) :direction :input)
   (loop :for i :from 0 :to (1- lnt) :do
       (setf (aref arr i 0) (read-from-string (nth (1- column) (split-sequence:SPLIT-SEQUENCE #\Space (read-line str))))))))

Спасибо всем за помощь.

2 голосов
/ 02 февраля 2012

Другой подход заключается в использовании читателя lisp для анализа данных в текстовом файле.Для этого я, вероятно, сначала преобразовал бы весь файл в строку, а затем вызвал бы

(eval (read-from-string (format nil "~a~a~a" "(initial wrapper code " str ")")))

Например, если вы хотите прочитать в файле данных все числа, разделенные пробеламиВ новой строке в списке предыдущая команда будет выглядеть так:

(eval (read-from-string (format nil "~a~a~a" "(list " str ")")))
...