Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

How to view a delimiter-separated-value file in Emacs with highlighting helpful for reading?

Ideally the delimiter character/string should be customizable.

If Emacs can't do, any other tool available on Linux for this task?

share|improve this question

4 Answers 4

Regarding @Ammar's solution It's not difficult to "fix" the command org-table-convert-region to take a regular expression for the separator, which in this case could be just %%. I added one line.

(defun 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
integer  When a number, use that many spaces as field 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."
  (interactive "rP")
  (let* ((beg (min beg0 end0))
         (end (max beg0 end0))
         re)
    (goto-char beg)
    (beginning-of-line 1)
    (setq beg (move-marker (make-marker) (point)))
    (goto-char end)
    (if (bolp) (backward-char 1) (end-of-line 1))
    (setq end (move-marker (make-marker) (point)))
    ;; Get the right field separator
    (unless separator
      (goto-char beg)
      (setq separator
            (cond
             ((not (re-search-forward "^[^\n\t]+$" end t)) '(16))
             ((not (re-search-forward "^[^\n,]+$" end t)) '(4))
             (t 1))))
    (goto-char beg)
    (if (equal separator '(4))
        (while (< (point) end)
          ;; parse the csv stuff
          (cond
           ((looking-at "^") (insert "| "))
           ((looking-at "[ \t]*$") (replace-match " |") (beginning-of-line 2))
           ((looking-at "[ \t]*\"\\([^\"\n]*\\)\"")
            (replace-match "\\1")
            (if (looking-at "\"") (insert "\"")))
           ((looking-at "[^,\n]+") (goto-char (match-end 0)))
           ((looking-at "[ \t]*,") (replace-match " | "))
           (t (beginning-of-line 2))))
      (setq re (cond
                ((stringp separator) separator) ;; <-- I added this line
                ((equal separator '(4)) "^\\|\"?[ \t]*,[ \t]*\"?")
                ((equal separator '(16)) "^\\|\t")
                ((integerp separator)
                 (if (< separator 1)
                     (error "Number of spaces in separator must be >= 1")
                   (format "^ *\\| *\t *\\| \\{%d,\\}" separator)))
                (t (error "This should not happen"))))
      (while (re-search-forward re end t)
        (replace-match "| " t t)))
    (goto-char beg)
    (org-table-align)))

Unfortunately, it doesn't escape | which is very frustrating to me, and also won't handle quotes at all. Assuming that the delimiter doesn't appear in a cell, it shouldn't be hard to write a function which will replace | with something else (e.g. \vert{} if you plan to export to LaTeX, or ⏐ which is the unicode character VERTICAL LINE EXTENSION) and then run the modified version of org-table-convert-region. You could even replace "%% and %%" with %% if you wish. Of course I have used %% as a standin for whatever delimiter you want (which could be an argument to the function).

It all depends on how often you are going to be looking at such files and what capabilities you need to know how much work you want to put into it. :-)

share|improve this answer

You might change the delimiter to | (e.g. by sed, but first replace all |'s by something else), add one | to every line beginning and line end, then open the file in emacs in org-mode.

You can also use csv-mode and its csv-align-fields.

share|improve this answer
    
This wouldn't work AFAIK as the cell content can contain |. –  qazwsx Jan 31 '12 at 20:09

In emacs you can highlight some text with highlight-phrase (M-s h p) or highlight-regexp (M-s h r).

share|improve this answer

If you have org-mode, then open the CSV file, set the major mode to org-mode, mark the whole buffer, and click C-|, to transform the CSV file to an org-mode table.

You can do anything to org-mode tables, combined with emacs' calc, it's more powerful than a spreadsheet application, see here for reference.

For linux, there are endless tools that you could use to process CSV files, but the swiss knife must be awk. Learn awk if you can, it will make your life easier.

share|improve this answer
    
This is not CSV, but a DSV, where the delimiter has been chosen by another person to be %%. Will what you said work for this situation? –  qazwsx Jan 31 '12 at 20:08
    
Well, looking at org-mode documentation it seem that the field separator for the command C-| is fixed to either n spaces, comma, or tab. What you can do is do a query-regexp-replace and replace the %% with comma or tab then convert it to a table. If the comma conflicts with the cell contents then do a query-regexp-replace with the regexp %%\(.*,.*\)%% and the replacement %%"\1"%% to quote the offending cells. –  Ammar Abdulaziz Feb 1 '12 at 1:09
    
Does the recipe for escaping comma also work for space and tab? So org-mode treats strings quoted by " as cells? –  qazwsx Feb 1 '12 at 5:42
    
Actually, no it doesn't. I tested it yesterday and it somehow worked, but not always. You could replace all commas with a unique character, then replace the delimiter with comma, then replace the unique characters to commas after converting to an org table. But that is probably too much of a hassle. –  Ammar Abdulaziz Feb 1 '12 at 17:42

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.