Я пытаюсь создать оргтаблицу на основе содержимого CSV-файла, в котором используется ";" как разделитель.
Я думал, что было бы легко иметь блок исходного кода для "cat" содержимого файла, а затем передать результат функции, которая создает таблицу, но я застрял: я не могу найти способ использовать " результаты" первого блока исходного кода. Функция, которую я знаю (org-table-convert-region), ожидает, что регион будет работать, и я не знаю, как передать текст "cat" в качестве региона.
#+NAME: csvraw
#+BEGIN_SRC sh :results raw
cat afile.csv
#+END_SRC
Я был бы признателен за вашу помощь в создании блока кода, который создает орг-таблицу из моего CSV-файла, который содержит строки, подобные следующим:
ID;Region;SubRegion;Area;No
1234;Asia;India;45;2
24251;Europe;Romania;456;67
(defun jea-convert-csv-to-org-table (fname)
(interactive "fCSV to convert: ")
(let ((result '("|-\n")))
(with-temp-buffer
(save-excursion (insert-file-contents-literally fname))
(while (and (not (eobp)) (re-search-forward "^\\(.+\\)$" nil t nil))
(push (concat "|" (replace-regexp-in-string ";" "|" (match-string 1)) "|\n")
result))
(push '"|-\n" result))
(concat (seq-mapcat #'identity (reverse result)))))
установите код elisp в файл ~/.emacs и перезапустите emacs. Или, еще лучше, eval
его существование (CTRL+x, CTRL+e или ALT+x eval-last-sexp).
#+NAME: csvraw
#+BEGIN_SRC elisp :results raw
(jea-convert-csv-to-org-table "/Users/jamesanderson/Downloads/test1.csv")
#+END_SRC
обратите внимание на изменение elisp
с sh
выше. вот гифка в действии:
emacs конвертирует csv в таблицу org
Код не оптимизирован для больших файлов и, честно говоря, довольно быстро собирается. Но, после небольшого тестирования, похоже, работает.
Джеймс, большое спасибо за ваш ответ и за то, что нашли время, чтобы ответить на мой запрос. Я следовал вашим инструкциям, используя пример файла csv, упомянутый в моем вопросе, но что-то идет не так: функция создает новый буфер и копирует содержимое csv файл есть, но зависает, вынуждая меня <kbd>Ctrl-g</kbd>
несколько раз восстановить контроль над emacs.
@jenesaisquoi, спасибо, что предложили улучшения. Попробую вашу версию и отпишусь здесь, когда закончу.
@jenesaisquoi правильно: я использовал Edebug, чтобы выяснить, что происходит, и действительно, цикл while продолжается вечно: он продолжает объединять строку |\n
с result
.
Джеймс, я изменил предложенный вами код, добавив условие завершения цикла while. Я отредактировал ваш ответ, чтобы отразить изменение: я думаю, мне придется подождать, пока поправка будет рассмотрена экспертами, чтобы она стала видимой.
@jenesaisquoi Ваша версия работает очень хорошо, спасибо! Я убрал условие not(eobp)
из вашего кода и использовал его в Джеймсе.
это большие улучшения. Я постоянно забываю о with-temp-buffer
. и я должен был протестировать его с более чем одним простым файлом. Я использую org-mode, но у меня никогда не было времени копаться в его коде. Я подозреваю, что в нем есть функции, которые могли бы работать еще лучше. Тем не менее, писать на lisp весело.
Написание лиспа является весело, но рабочим предположением всегда должно быть: «в организационном режиме уже должно быть что-то встроенное для этого» для любого значения «this». Смотрите мой ответ для доказательства в этом конкретном случае :-)
Существует org-table-convert-region
(связанный с C-c |
), который может довольно просто выполнить преобразование. Единственный трюк — указать ;
в качестве разделителя. Вы можете сделать это, вызвав его с правильным аргументом префикса - строка документа говорит:
(org-table-convert-region BEG0 END0 &optional SEPARATOR)
Convert region to a table.
The region goes from BEG0 to END0, but these borders will be moved
slightly, to make sure a beginning of line in the first line is included.
SEPARATOR specifies the field separator in the lines. It can have the
following values:
(4) Use the comma as a field separator
(16) Use a TAB as field separator
(64) Prompt for a regular expression as field separator
integer When a number, use that many spaces, or a TAB, as field separator
regexp When a regular expression, use it to match the separator
nil When nil, the command tries to be smart and figure out the
separator in the following way:
- when each line contains a TAB, assume TAB-separated material
- when each line contains a comma, assume CSV material
- else, assume one or more SPACE characters as separator.
Значение (64)
— всего три C-u
подряд, поэтому процесс выглядит следующим образом:
C-x i
.C-x C-x
, чтобы пометить вставленное содержимое как активную область.C-u C-u C-u C-c | ; RET
Что еще круче, если оставить пустую строку в CSV-файле между первой строкой и остальными строками, первая строка автоматически станет заголовком в таблице.
И вы также можете обернуть его в блок кода:
#+begin_src elisp :var file = "/tmp/foo.csv" :results raw
(defun csv-to-table (file)
(with-temp-buffer
(erase-buffer)
(insert-file file)
(org-table-convert-region (point-min) (point-max) ";")
(buffer-string)))
(csv-to-table file)
#+end_src
#+RESULTS:
| a | b | c |
|---+---+---|
| d | e | f |
| g | h | i |
Большое спасибо, что откликнулись на ваш очень информативный ответ. Решение, которое вы предлагаете, компактно и при этом чрезвычайно «разборчиво».
Вы могли бы повысить эффективность, просто изменив текст буфера и извлекая его весь сразу,
(defun nvp-convert-csv-to-org-table (fname) (interactive (list (read-file-name "CSV to convert: "))) (with-temp-buffer (save-excursion (insert-file-contents-literally fname)) (while (not (eobp)) (insert "|") (while (search-forward ";" (line-end-position) 'move) (replace-match "|")) (insert "|") (forward-line)) (buffer-string)))