Вы можете использовать тот факт, что парсер Лиспа доступен для пользователя Лиспа. Проблема с этими данными заключается в том, что некоторые значения содержат двоеточия, при этом в Common Lisp используется разделитель имени пакета. Я сделал некоторый рабочий код Common Lisp для решения вашего вопроса, но мне пришлось обойти упомянутую проблему, определив соответствующие пакеты.
Вот код, который, конечно, должен быть расширен (следуя тем же шаблонам, которые уже использованы в нем) для всего, что вы пропустили в примере в вашем вопросе:
(defpackage #:thous
(:export #:5-10 #:20+))
(defpackage #:private
(:export #:roman-catholic))
(defstruct (college (:conc-name nil))
(name "")
(state "")
(location "")
(control "")
(no-of-students ""))
(defun data->college (name data)
(let ((college (make-college :name (write-to-string name :case :capitalize))))
(loop for (key value) in data
for string = (remove #\| (write-to-string value :case :downcase))
do (case key
(state (setf (state college) string))
(location (setf (location college) string))
(control (setf (control college) string))
(no-of-students (setf (no-of-students college) string))))
college))
(defun read-data (stream)
(loop for (def-instance name . data) = (read stream nil nil)
while def-instance
collect (data->college name data)))
(defun print-college-as-csv (college stream)
(format stream
"~a~{,~a~}~%"
(name college)
(list (state college)
(location college)
(control college)
(no-of-students college))))
(defun data->csv (in out)
(let ((header (make-college :name "College"
:state "state"
:location "location"
:control "control"
:no-of-students "no-of-students")))
(print-college-as-csv header out)
(dolist (college (read-data in))
(print-college-as-csv college out))))
(defun data-file-to-csv (input-file output-file)
(with-open-file (in input-file)
(with-open-file (out output-file
:direction :output
:if-does-not-exist :create
:if-exists :supersede)
(data->csv in out))))
Основной функцией является data-file-to-csv, которую можно вызвать с помощью (data-file-to-csv "path-to-input-file" "path-to-output-file")
в REPL Common Lisp после загрузки этого кода.
РЕДАКТИРОВАТЬ: некоторые дополнительные мысли
На самом деле было бы проще, вместо добавления определений пакетов для всех значений с двоеточиями, выполнять поиск по регулярным выражениям и заменять данные, чтобы добавлять кавычки (") вокруг всех значений. Это заставит Lisp анализировать их как строки В этом случае можно удалить строку for string = (remove #\| (write-to-string value :case :downcase))
и заменить string
на value
во всех строках оператора case
.
Из-за высокой регулярности данных даже не нужно вообще анализировать определения Lisp вообще. Вместо этого вы можете просто извлечь данные с помощью регулярных выражений. Язык, особенно подходящий для преобразования текстовых файлов на основе регулярных выражений, вполне подойдет для этой работы, например AWK или Perl.