2013-04-18 8 views
5

Rozważmy następujący przypadek: mam pewne dane, które wygląda następująco:Format danych: aby kolumny na wiersze (i odwrotnie)

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

Należy zauważyć, że znak dolara oddzielający dwie kolumny może być dowolnym znakiem (od pewnej liczby spacji, znaku \ t (tab), przecinka lub po prostu dowolnego znaku, który jest unikatowo używany do oddzielania kolumny. Zwróć też uwagę, że dane mogą mieć więcej niż dwie kolumny.

Teraz chciałbym sformatować blok danych tak, aby wszystkie elementy z określonej kolumny były wymienione w jednym wierszu (oddzielone znakiem, który oznaczyłem jako $ w powyższym przykładzie): Elementy z kolumny 0 wypełnić wiersz 0, elementy z kolumny 1 wypełnić wiersz 1 i tak dalej.

Czy jest do tego predefiniowana funkcja emacs? A jeśli nie, czy jest jakaś funkcja "samoczynnie zwinięta", aby to osiągnąć?

Również jestem bardzo zainteresowany funkcją, która wykonuje odwrotną rzecz, tj. Bierze pewne linie i umieszcza je w strukturze kolumny.

Każda pomoc jest doceniana!

Odpowiedz

6

Można użyć csv-mode (dostępny od package.el). Jest to prosta operacja transpozycji. Aby to zrobić, dostosuj wartość csv-separators do '("$"), a następnie użyj C-c C-t.

+0

ten działa częściowo, po transpozycji mi brakuje separator char pomiędzy różnymi pozycjami w rzędzie. – elemakil

+0

Działa tutaj. Czy używasz dostosowywania, aby ustawić zmienną i ponownie uruchomić emacs? Miałem problemy, gdy ustawiłem zmienną bezpośrednio w sesji. –

1

Właśnie przez wzgląd na praktyki:

(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")))))) 

Może przy użyciu jednego z csv-mode byłaby lepsza, ale można spróbować tego względu :)

Jak to działa: jeśli nazwać jak Mxtranspose-table, wtedy zakładamy, że kolumny tabeli są oddzielone pojedynczym białej przestrzeni, jeśli jednak wywołać go z argumentem numerycznym (np M-3Mxtranspose-table, wówczas pojawi się monit o zebranie 3 separatorów kolumn. Można też nazwać jak C-uC-uM-xtranspose-table i zrezygnować z dostarczania wszystkie 16 separatorów naciskając RET pytany o dodatkowym separatorem.

nie mogłem znaleźć odpowiedniego porządkowej funkcji drukowania numerów ... tak, przepraszam za „1'th” i „2'th” angielski :)

+0

Tego właśnie szukałem (coś niezależnego od trybu, którego aktualnie używam), ale ma kilka błędów. Na początek wydaje się, że stracił ostatnią kolumnę. Działając na dwóch kolumnach otrzymuję jeden wiersz (zawierający pozycje z pierwszej kolumny), pracując na trzech otrzymuję dwa wiersze i tak dalej. Ponadto okazuje się, że argument przedrostka nie działa, wykonanie 'M-3 Mx transpose-table' daje błąd' let *: Wrong type argument: listp, 3' Również odwrotność (od wiersza do kolumn) zostaje utracona ostatnia pozycja (8 wierszy na col -> 1 wiersz na "col" -> 7 wierszy na col). – elemakil

Powiązane problemy