55

Emacs has a very nice extension by the name of org-mode.

I would like to be able to easily load CSV files into org-mode without significant grief. All I've been able to find is table-import or table-capture, which, simply put, don't work even approximately well.

Note that part of my issue is text strings with a comma within them. 1,2,3,4 is different than 1,2,"3,4".

Is there a function out there or a perl script that one could run to transform a csv file into org-mode format?

Thanks!

Paul Nathan
  • 39,638
  • 28
  • 112
  • 212
  • Take a look if http://code.google.com/p/csvfix/ by Neil Butterworth. It has CSV->XML conversion, so maybe you could use that as a part of the solution. – Andrew Y Aug 06 '09 at 22:13
  • Only partly related, but still worthwhile reading for anyone who isn't already aware of the number of edge cases CSV presents: https://tburette.github.io/blog/2014/05/25/so-you-want-to-write-your-own-CSV-code/ –  Feb 08 '16 at 20:14

5 Answers5

90

From the org-mode manual:

C-c | Convert the active region to table. If every line contains at least one TAB character, the function assumes that the material is tab separated. If every line contains a comma, comma-separated values (CSV) are assumed. If not, lines are split at whitespace into fields. You can use a prefix argument to force a specific separator: C-u forces CSV, C-u C-u forces TAB, and a numeric argument N indicates that at least N consecutive spaces, or alternatively a TAB will be the separator. If there is no active region, this command creates an empty Org table.

So just paste the data into an org file, select it, and do C-u C-c | .

Don Womick
  • 990
  • 6
  • 7
  • Hmm, looks like the "fi" ligatures in the PDF got dropped out of the quote above... anyway... "elds" should be "fields," "specic" should be "specific," and "prex" should be "prefix." – Don Womick Aug 07 '09 at 22:16
  • 4
    Doesn't work when you have CSV fields that contain commas, which the OP specifies... – genehack Aug 08 '09 at 00:49
  • 1
    Even the auto-detect (without leading C-u) works fine for CSV with embedded commas in the (quoted) values. – user98761 Feb 02 '14 at 19:59
  • 13
    Just in case (like me) your key bindings are screwed up and C-u C-c | is not working, the direct function to call (after selecting a region to convert) is *M-x org-table-convert-region* – mike May 20 '14 at 05:37
  • 3
    @DonWomick This does not work if the data has commas and newlines wrapped in double quotes: `a,b,c,"def, ghi"` – Kaushal Modi Apr 06 '15 at 18:40
  • 1
    The above comment is right, unless I am missing something. @DonWomick 's answer does not answer the OP's question about commas and newlines wrapped in quotes. How can I convert to a table when there are commas/newlines wrapped in quotes for my csv fields? – modulitos Aug 05 '15 at 10:30
7

Have a look at:

C-h f org-table-convert-region

I'm always converting csv so I added this to my .emacs.

(defun org-convert-csv-table (beg end)
  (interactive (list (mark) (point)))
  (org-table-convert-region beg end ",")
  )

(add-hook 'org-mode-hook
      (lambda ()
    (define-key org-mode-map (kbd "<f6>") 'org-convert-csv-table)))

update

Here is another function that considers the quoted commas as well :

 a,"12,12",b --> a | 12,12 |b

feel free to improve it :-).

(defun org-convert-csv-table (beg end)
  ; convert csv to org-table considering "12,12"
  (interactive (list (point) (mark)))
  (replace-regexp "\\(^\\)\\|\\(\".*?\"\\)\\|," (quote (replace-eval-replacement
                            replace-quote (cond ((equal "^" (match-string 1)) "|")
                                                   ((equal "," (match-string 0)) "|")
                                                   ((match-string 2))) ))  nil  beg end)
DJJ
  • 2,481
  • 2
  • 28
  • 53
5

I'm assuming you want to convert your CSV specifically into org-mode tables. If that's not the case, you may want to be more explicit about output format in your question.

Something like this should do it, or at least get you a starting point you can hack on:

  #!/usr/bin/perl

  use strict;
  use warnings;

  use Text::CSV;

  my $csv = Text::CSV->new();

  while ( my $line = <DATA> ) {
    if ( $csv->parse( $line )) {
      my $str = join '|' , $csv->fields();
      print "|$str|\n";
    }
  }


  __DATA__
  1,2,3,4
  1,2,"3,4"
genehack
  • 136,130
  • 1
  • 24
  • 24
4

Try this:

;; Insert a file and convert it to an org table
(defun aleblanc/insert-file-as-org-table (filename)
  "Insert a file into the current buffer at point, and convert it to an org table."
  (interactive (list (ido-read-file-name "csv file: ")))
  (let* ((start (point))
    (end (+ start (nth 1 (insert-file-contents filename)))))
    (org-table-convert-region start end)
    ))
2

Here is a bit of a hack-job, but it works.

when you export the CSV file, force quotes around each entry, then replace all "," as a vertical bar.

Finally, I make a macro that does something like this:

C-a    ; Beginning-of-line
|      ; Self-insert-char
C-e    ; end-of-line
|      ; Self-insert-char
<down> ; Down one line

(I am not 100% sure if | is a self-insert-char or not, so its best to record your own macro)

Hit tab somewhere in the middle of the table, and org-mode formats it properly. I find this easier to do in a narrowed region.

Caveat: If you have a vertical bar in your input.. it probably won't work quite right. Situations like that should be easy to spot, and relatively easy to fix.

Generally, when importing something text-like into org-mode, I have found a combination of some smart macro writing, and search-replace to be the easiest way

I hope that helps.

Jonathan Arkell
  • 10,526
  • 2
  • 24
  • 32