Другое

Руководство SBCL: Запись списков с контролем длины строк

Узнайте, как форматировать и записывать списки списков в файлы в SBCL с контролем длины строк. Изучите техники красивой печати, динамические переменные и пользовательские решения для читаемых выходных файлов.

Как форматировать и записывать списки списков в файл в SBCL с контролируемой длиной строки?

В пакете Common Lisp, который я разрабатываю, я часто работаю со списками списков, где отдельные списки содержат множество элементов. При записи их в файл с помощью (write stream list) полученные строки становятся чрезвычайно длинными и трудными для чтения.

Например, при записи этих данных:

lisp
((IT0005204729 4AIM-SICAF AFF FINANC FSMISC EUR 281 106 9.7029 -0.0022 - -
  2.85714 5.65861 -11.76471 -37.2166 -32.07547 -35.287365 -165.4584 - - -
  -4.69812 0.43549 - -76.98278 -17.01118 -16.69684 3.6809604 -2.9394858
  -22.814877 4.75634 -4.0883703 -20.47732 51.963356 83.06184 55.33002 1.6398745
  -158.82921 31.904535 -21.005991 -49.310223 - UP 0)
 (IT0005440323 4AIM-SICAF-C2CR AFF FINANC FSMISC EUR 281 - 9.7029 -0.0022 - -
  2.85714 5.65861 -11.76471 -37.2166 -32.07547 NA -165.4584 - - - -4.69812
  0.43549 - -76.98278 -17.01118 -16.69684 - - - - - - - - - - -158.82921 20
  -21.005991 -53.2784 - UP 0)
 (IT0001233417 A2A AFF UTILIT ELECTU EUR 1.38 13415263 4899.864 0.9599 5.78005
  0.08166 -4.54684 -8.24289 13.33333 -6.09427 25.62249 40.853104 52.60864
  31.9303 67.94521 3.84002 365 1.20865 9.86191 0.15859 12.20054 4.96296
  -2.4322445 3.5466106 20.909727 -3.233147 3.4399962 16.768408 45.12124
  27.513227 60.48246 -0.010872668 47.46384 27.35368 -0.6957139 24.707268 2.1667
  UP 0))

Какой лучший подход для форматирования вывода так, чтобы каждый список записывался с контролируемой длиной строки для лучшей читаемости? Существуют ли специфические функции SBCL или методы для форматирования больших списков при записи в файлы?

Для форматирования и записи списков списков в файл в SBCL с контролируемой длиной строки следует использовать систему красивого вывода Common Lisp с такими параметрами, как :right-margin, :pretty, или устанавливать динамические переменные, такие как *print-right-margin*. Лучший подход включает использование функции write с аргументами красивого вывода или функции format с соответствующими директивами форматирования для обеспечения читаемой длины строк.

Содержание

Использование функции Write с красивым выводом

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

lisp
(with-open-file (stream "output.txt" :direction :output :if-exists :supersede)
  (write your-list-of-lists :stream stream 
         :pretty t                ; Включить красивый вывод
         :right-margin 80        ; Установить правое поле в 80 символов
         :escape nil             ; Не экранировать специальные символы
         :miser-width 20))        ; Использовать miser-стиль, если в пределах 20 символов от правого поля

Согласно Common Lisp HyperSpec, функция write принимает ключевые аргументы, включая :right-margin, :pretty и :miser-width, которые соответствуют динамическим переменным, управляющим поведением красивого вывода.

Динамические переменные для управления выводом

Вы также можете управлять форматированием вывода, устанавливая динамические переменные перед записью:

lisp
(let ((*print-pretty* t)           ; Включить красивый вывод
      (*print-right-margin* 80)   ; Установить правое поле в 80 символов
      (*print-miser-width* 20))   ; Использовать miser-стиль в пределах 20 символов
  (with-open-file (stream "output.txt" :direction :output :if-exists :supersede)
    (write your-list-of-lists :stream stream)))

Как объясняется в документации красивого вывода Lisp, правое поле контролируется переменной *print-right-margin*, и красивый вывод автоматически будет вставлять разрывы строк, когда контент превышает этот лимит.

Подход с использованием функции Format

Функция format предоставляет обширные возможности форматирования. Вы можете использовать ее для форматирования списков с контролируемой длиной строки:

lisp
(with-open-file (stream "output.txt" :direction :output :if-exists :supersede)
  (format stream "~{~{~A~^ ~}~%~}" your-list-of-lists))

Для более сложного форматирования можно использовать директивы format, контролирующие разрывы строк:

lisp
(defun write-list-with-controlled-line-length (list stream max-line-length)
  "Записать список в поток с контролируемой длиной строки"
  (let ((current-line-length 0)
        (words (mapcar #'princ-to-string list)))
    (dolist (word words)
      (let ((word-length (length word)))
        (when (> (+ current-line-length word-length 1) max-line-length)
          (format stream "~%")
          (setf current-line-length 0))
        (format stream "~A" word)
        (incf current-line-length word-length)
        (unless (eq word (car (last words)))
          (format stream " ")
          (incf current-line-length 1))))))

Решения для переноса строк

Для более точного контроля над разрывами строк можно реализовать собственный перенос строк:

lisp
(defun write-list-with-line-wrap (list stream max-line-length)
  "Записать список в поток с автоматическим переносом строк"
  (let ((current-line 0))
    (dolist (item list)
      (let* ((item-str (princ-to-string item))
             (item-len (length item-str)))
        (when (> (+ current-line item-len 1) max-line-length)
          (format stream "~%")
          (setf current-line 0))
        (format stream "~A" item-str)
        (incf current-line item-len)
        (unless (eq item (car (last list)))
          (format stream " ")
          (incf current-line 1))))))

Затем можно использовать эту функцию с with-open-file:

lisp
(with-open-file (stream "output.txt" :direction :output :if-exists :supersede)
  (dolist (sublist your-list-of-lists)
    (write-list-with-line-wrap sublist stream 80)
    (format stream "~%")))

Полный практический пример

Вот полное решение, обрабатывающее вашу конкретную структуру данных:

lisp
(defun write-formatted-lists-to-file (filename list-of-lists &optional (max-line-length 80))
  "Записать списки списков в файл с контролируемой длиной строки"
  (with-open-file (stream filename 
                         :direction :output 
                         :if-exists :supersede
                         :external-format :utf-8)
    (dolist (list-item list-of-lists)
      ;; Использовать write с красивым выводом для автоматического форматирования
      (write list-item :stream stream 
             :pretty t
             :right-margin max-line-length
             :escape nil
             :miser-width 20)
      ;; Добавить новую строку между списками
      (format stream "~%")))

Для ваших конкретных примеров данных:

lisp
(defvar *sample-data*
  '((IT0005204729 4AIM-SICAF AFF FINANC FSMISC EUR 281 106 9.7029 -0.0022 - -
     2.85714 5.65861 -11.76471 -37.2166 -32.07547 -35.287365 -165.4584 - - -
     -4.69812 0.43549 - -76.98278 -17.01118 -16.69684 3.6809604 -2.9394858
     -22.814877 4.75634 -4.0883703 -20.47732 51.963356 83.06184 55.33002 1.6398745
     -158.82921 31.904535 -21.005991 -49.310223 - UP 0)
    (IT0005440323 4AIM-SICAF-C2CR AFF FINANC FSMISC EUR 281 - 9.7029 -0.0022 - -
     2.85714 5.65861 -11.76471 -37.2166 -32.07547 NA -165.4584 - - - -4.69812
     0.43549 - -76.98278 -17.01118 -16.69684 - - - - - - - - - - -158.82921 20
     -21.005991 -53.2784 - UP 0)
    (IT0001233417 A2A AFF UTILIT ELECTU EUR 1.38 13415263 4899.864 0.9599 5.78005
     0.08166 -4.54684 -8.24289 13.33333 -6.09427 25.62249 40.853104 52.60864
     31.9303 67.94521 3.84002 365 1.20865 9.86191 0.15859 12.20054 4.96296
     -2.4322445 3.5466106 20.909727 -3.233147 3.4399962 16.768408 45.12124
     27.513227 60.48246 -0.010872668 47.46384 27.35368 -0.6957139 24.707268 2.1667
     UP 0)))

;; Запись с контролируемой длиной строки
(write-formatted-lists-to-file "formatted_output.txt" *sample-data* 80)

Если вам нужен более точный контроль над форматированием, вы также можете использовать красивый вывод напрямую с pprint:

lisp
(with-open-file (stream "output.txt" :direction :output :if-exists :supersede)
  (let ((*print-right-margin* 80))
    (dolist (item list-of-lists)
      (pprint item stream)
      (format stream "~%"))))

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

Источники

  1. Руководство пользователя SBCL 2.5.10 - Ввод-вывод файлов
  2. Common Lisp HyperSpec - Функция Write
  3. Документация красивого вывода Lisp
  4. Stack Overflow - Запись списков в файлы с контролируемой длиной
  5. Common Lisp Cookbook - Файлы и каталоги

Заключение

Для эффективного форматирования и записи списков списков в файлы в SBCL с контролируемой длиной строки:

  1. Используйте систему красивого вывода с функцией write и параметром :right-margin для автоматического интеллектуального форматирования
  2. Устанавливайте динамические переменные, такие как *print-right-margin* и *print-pretty*, для управления форматированием вывода
  3. Рассмотрите возможность использования переноса строк для более точного контроля, когда красивый вывод недостаточен
  4. Используйте директивы format для конкретных требований форматирования и контроля разрывов строк
  5. Тестируйте с вашими реальными данными, чтобы настроить параметры, такие как :miser-width и поля длины строки

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

Авторы
Проверено модерацией
Модерация