格式数据:使列到行(和其他方式)

时间:2013-04-18 16:36:18

标签: emacs elisp

考虑这种情况:我有一些看起来像这样的数据:

  

1.9170000e + 03 $ 1.6909110e + 00
  1.4550000e + 03 $ 1.7775459e + 00
  1.1800000e + 03 $ 1.8771469e + 00
  1.0000000e + 03 $ 1.9992190e + 00
  8.7500000e + 02 $ 2.1938025e + 00
  7.8300000e + 02 $ 2.5585915e + 00

请注意,分隔两列的美元符号可以是任何字符(范围从一定数量的空格,\ t(制表符)字符,逗号或任何唯一用于分隔列的字符)另请注意,数据可能包含两列以上。

现在我想重新格式化数据块,使得某一列中的所有项都列在一行中(由我在上面示例中标记为$的char分隔):第0列中的项填充第0行,第1列中的项填充第1行,依此类推。

是否有预定义的emacs功能?或者如果没有,是否有一些“自动滚动”功能来实现这一目标?

此外,我对一个执行相反操作的函数非常感兴趣,即取一些行并将它们放在列结构中。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:7)

您可以使用csv-modepackage.el提供)。这是一个简单的转置操作。为此,请自定义csv-separators'("$")的值,然后使用 C-c C-t

答案 1 :(得分:1)

仅为了练习:

(defun transpose-table (begin end &optional numcols)
  (interactive "r\nP")
  (save-excursion
    (goto-char begin)
    (move-beginning-of-line 1)
    (let ((separators
           (if numcols
               (loop for i from 0 upto
                     (if (numberp numcols) numcols (car numcols))
                     for sep =
                     (read-string
                      (format "%d'th column separator (RET to terminate): " i))
                     until (string= sep "")
                     collect sep)
             (let ((x (list " "))) (nconc x x))))
          (end (save-excursion
                 (goto-char end)
                 (move-end-of-line 1)
                 (point))) lines)
      (loop while (< (point) end)
            for start = (point)
            for line = (buffer-substring 
                        start 
                        (progn (move-end-of-line 1) (point)))
            for numlines from 0
            with numrows = 0
            with longest-word = 0
            collect (loop for i from 0 below (length line)
                          with last-pos = 0
                          with rows = 0
                          with sep = separators
                          for sep-length = (length (car sep))
                          if (and (< (+ sep-length i) (length line))
                                  (string= (car sep)
                                           (substring line i (+ i sep-length))))
                          collect (substring line last-pos i) into words
                          and do (setf longest-word (max longest-word (- i last-pos))
                                       last-pos (+ i sep-length)
                                       sep (cdr sep) rows (1+ rows))
                          end
                          finally (return
                                   (progn
                                     (setf numrows (max rows numrows))
                                     (if (< last-pos (length line))
                                         (append words (list (substring line last-pos)))
                                       words))))
            into lines
            collect longest-word into word-lengths
            do (unless (eobp) (forward-char))
            finally 
            (loop initially (delete-region begin end)
                  for i from 0 to numrows do
                  (loop for line on lines 
                        for cell-length in word-lengths do
                        (if (caar line)
                            (let ((insertion (caar line)))
                              (insert insertion
                                      (make-string
                                       (- cell-length (length insertion) -1) ?\ ))
                              (rplaca line (cdar line)))
                          (insert (make-string (1+ cell-length) ?\ ))))
                  (insert "\n"))))))

使用csv-mode中的那个实际上会更好,但无论如何都可以尝试这个:)

如何工作:如果你将其称为 Mx transpose-table,那么它将假设表列由单个空格分隔,但是,如果使用数字参数调用它(例如, M-3 Mx transpose-table,然后它将提示您收集3个列分隔符。您也可以将其称为 Cu Cu Mx transpose-table,当要求提供额外的分隔符时,按 RET 选择不提供所有16个分隔符。

我找不到合适的序号打印功能......所以,对不起“1”和“2”英语:)