2013-04-18 13 views
5

Consideriamo questo caso: ho alcuni dati che assomiglia a questo:Formato dati: rendere le colonne di righe (e viceversa)

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

Si noti che il simbolo del dollaro che separa le due colonne può essere qualsiasi carattere (che va da un certo numero di spazi, il carattere \ t (tab), una virgola o qualsiasi carattere che viene utilizzato in modo univoco allo scopo di separare la colonna. Si noti inoltre che i dati potrebbero avere più di due colonne.

Ora mi piacerebbe riformattare il blocco di dati in modo che tutti gli elementi di una determinata colonna siano elencati in una singola riga (separati dal carattere che ho contrassegnato come $ nell'esempio precedente): Gli elementi dalla colonna 0 riempire la riga 0, gli elementi dalla colonna 1 riempiono la riga 1 e così via.

Esiste una funzione emacs predefinita per farlo? O se no, c'è qualche funzione "auto-rollata" per raggiungerlo?

Anche io sono molto interessato a una funzione che fa l'inverso, cioè prendere alcune linee e metterle nella struttura della colonna.

Qualsiasi aiuto è molto apprezzato!

risposta

6

È possibile utilizzare csv-mode (disponibile da package.el). Questa è una semplice operazione di trasposizione. Per fare ciò, personalizzare il valore di csv-separators a '("$") e quindi utilizzare C-c C-t.

+0

Questo funziona in parte, dopo la trasposizione mi manca il char separatore tra i diversi elementi nella riga. – elemakil

+0

Funziona qui. Hai usato personalizzare per impostare la variabile e riavviare emacs? Ho avuto problemi quando ho impostato la variabile direttamente nella sessione. –

1

Solo per il gusto di pratica:

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

Forse utilizzando quello da csv-mode sarebbe effettivamente meglio, ma si può provare questo a prescindere :)

Come funziona: se lo si chiama come Mxtranspose-table, allora si assume che le colonne della tabella sono separate da singolo spazio bianco, tuttavia, se lo si richiama con argomento numerico (ad esempio, M-3Mxtranspose-table, quindi verrà richiesto di raccogliere 3 separatori di colonne. Si potrebbe anche chiamare come C-uC-uM-xtranspose-table, e scegliere di fornire tutti i 16 separatori premendo RET quando gli viene chiesto per la separazione in più.

non riuscivo a trovare una corretta stampa ordinale della funzione numeri ... così, mi spiace per "1'th" e "2'th" inglese :)

+0

Questo è quello che stavo cercando (qualcosa di indipendente dalla modalità che sto usando attualmente) ma ha alcuni bug. Per i principianti, sembra perdere l'ultima colonna. Correndo su due colonne ottengo una riga (contenente gli elementi della prima colonna), lavorando su tre ottengo due righe e così via. Inoltre, sembra che l'argomento prefisso non funzioni, eseguendo 'M-3 Mx transpose-table' restituisce l'errore' let *: argomento tipo errato: listp, 3' Anche il contrario (riga per colonne) perde l'ultima voce (8 righe per colonna -> 1 riga per "colonna" -> 7 righe per colonna). – elemakil

Problemi correlati