Создание организационных таблиц из результатов блока кода

#emacs #org-mode #org-babel

#emacs #org-режим #org-babel

Вопрос:

Я пытаюсь создать организационную таблицу на основе содержимого файла CSV, который использует «;» в качестве разделителя.

Я думал, что было бы легко создать блок исходного кода для «cat» содержимого файла, а затем передать результат функции, которая создает таблицу, но я застрял: я не могу найти способ использовать «результаты» первого блока исходного кода. Функция, которую я знаю (org-table-convert-region), ожидает, что регион будет работать, и я не знаю, как передать текст «cat» в качестве региона.

 # NAME: csvraw
# BEGIN_SRC sh :results raw
  cat afile.csv
# END_SRC
  

Я был бы признателен за вашу помощь в создании блока кода, который создает org-table из моего csv-файла, который содержит строки, подобные следующим:

 ID;Region;SubRegion;Area;No
1234;Asia;India;45;2
24251;Europe;Romania;456;67
  

Ответ №1:

Существует org-table-convert-region (привязанный к C-c | ), который может выполнить преобразование довольно просто. Единственный трюк — указать ; в качестве разделителя. Вы можете сделать это, вызвав его с соответствующим префиксным аргументом — строка документа гласит:

 (org-table-convert-region BEG0 END0 amp;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 в строке, поэтому процесс выглядит следующим образом:

  • вставьте файл CSV с 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 |
  

Комментарии:

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

Ответ №2:

 (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 from sh в приведенном выше. вот gif-изображение этого в действии:
emacs преобразует csv в org table

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

Комментарии:

1. Вы могли бы повысить эффективность, просто изменив текст буфера и извлекая его все сразу, (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)))

2. Джеймс, большое вам спасибо за ваш ответ и за то, что нашли время ответить на мой запрос. Я следовал вашим инструкциям, используя файл образца csv, упомянутый в моем вопросе, но что-то пошло не так: функция создает новый буфер и копирует туда содержимое файла csv, но зависает, заставляя меня <kbd>Ctrl-g</kbd> несколько раз восстанавливать контроль над emacs.

3. @jenesaisquoi, спасибо за предложение улучшений. Я собираюсь попробовать вашу версию и опубликовать здесь, когда закончу.

4. @jenesaisquoi правильно: я использовал Edebug, чтобы выяснить, что происходит, и, действительно, цикл while продолжается вечно: он продолжает |n объединять строку в result .

5. Джеймс, я внес изменения в предложенный вами код, добавив условие завершения для цикла while. Я отредактировал ваш ответ, чтобы отразить изменение: я думаю, мне придется подождать, пока поправка будет рассмотрена экспертами, чтобы она стала видимой.