2012-10-24 14 views
18

Ho un testo con un sacco di linee, la mia domanda è come eliminare le linee di ripetizione in emacs? utilizzando il comando nei pacchetti emacs o elisp senza utilità esterne.come eliminare le linee di ripetizione in emacs

ad esempio:

this is line a 
this is line b 
this is line a 

per rimuovere la linea 3 (lo stesso di prima linea)

this is line a 
this is line b 

risposta

15

inserire questo codice ai vostri .emacs:

(defun uniq-lines (beg end) 
    "Unique lines in region. 
Called from a program, there are two arguments: 
BEG and END (region to sort)." 
    (interactive "r") 
    (save-excursion 
    (save-restriction 
     (narrow-to-region beg end) 
     (goto-char (point-min)) 
     (while (not (eobp)) 
     (kill-line 1) 
     (yank) 
     (let ((next-line (point))) 
      (while 
       (re-search-forward 
       (format "^%s" (regexp-quote (car kill-ring))) nil t) 
      (replace-match "" nil nil)) 
      (goto-char next-line)))))) 

Usage:

M-x uniq-lines 
+1

Invece di usare il kill-ring, puoi semplicemente salvare il contenuto in una variabile associata a 'let'. –

+0

Grazie per il consiglio! – ymn

+0

Grazie per l'aiuto! – toolchainX

2
(defun unique-lines (start end) 
    "This will remove all duplicating lines in the region. 
Note empty lines count as duplicates of the empy line! All empy lines are 
removed sans the first one, which may be confusing!" 
    (interactive "r") 
    (let ((hash (make-hash-table :test #'equal)) (i -1)) 
    (dolist (s (split-string (buffer-substring-no-properties start end) "$" t) 
       (let ((lines (make-vector (1+ i) nil))) 
       (maphash 
        (lambda (key value) (setf (aref lines value) key)) 
        hash) 
       (kill-region start end) 
       (insert (mapconcat #'identity lines "\n")))) 
     (setq s       ; because Emacs can't properly 
             ; split lines :/ 
      (substring 
      s (position-if 
       (lambda (x) 
        (not (or (char-equal ?\n x) (char-equal ?\r x)))) s))) 
     (unless (gethash s hash) 
     (setf (gethash s hash) (incf i)))))) 

Un'alternativa:

  • non utilizzerà annullare la storia per memorizzare le partite.
  • Sarà in generale più veloce (ma se sei alla ricerca della massima velocità - costruisci un albero prefisso).
  • Ha l'effetto di sostituire tutti i precedenti caratteri di nuova riga, qualunque fosse con \n (stile UNIX). Quale può essere un bonus o uno svantaggio, a seconda della situazione.
  • Si potrebbe migliorare leggermente (più veloce), se si reimplementa split-string in modo che accetti caratteri anziché espressioni regolari.

po 'più lungo, ma, variante forse, un po' più efficiente:

(defun split-string-chars (string chars &optional omit-nulls) 
    (let ((separators (make-hash-table)) 
     (last 0) 
     current 
     result) 
    (dolist (c chars) (setf (gethash c separators) t)) 
    (dotimes (i (length string) 
       (progn 
       (when (< last i) 
        (push (substring string last i) result)) 
       (reverse result))) 
     (setq current (aref string i)) 
     (when (gethash current separators) 
     (when (or (and (not omit-nulls) (= (1+ last) i)) 
        (/= last i)) 
      (push (substring string last i) result)) 
     (setq last (1+ i)))))) 

(defun unique-lines (start end) 
    "This will remove all duplicating lines in the region. 
Note empty lines count as duplicates of the empy line! All empy lines are 
removed sans the first one, which may be confusing!" 
    (interactive "r") 
    (let ((hash (make-hash-table :test #'equal)) (i -1)) 
    (dolist (s (split-string-chars 
       (buffer-substring-no-properties start end) '(?\n) t) 
       (let ((lines (make-vector (1+ i) nil))) 
       (maphash 
        (lambda (key value) (setf (aref lines value) key)) 
        hash) 
       (kill-region start end) 
       (insert (mapconcat #'identity lines "\n")))) 
     (unless (gethash s hash) 
     (setf (gethash s hash) (incf i)))))) 
+1

Le righe nei buffer di Emacs sono sempre delimitate da \ n (indipendentemente dal delimitatore utilizzato nel file corrispondente). L'uso di \ r è sempre stato solo per il vecchio 'selective-display', che è stato reso obsoleto molti anni fa dalla proprietà' invisibile' delle sovrapposizioni e delle proprietà del testo. – Stefan

7

In Linux, selezionare regione, e digitare

M-| uniq <RETURN> 

Il risultato senza duplicati sono in nuovo buffer

+3

prefisso con C-u e sostituirà la tua regione con il risultato del comando shell – Santino

22

Se si dispone di Emacs 24.4 o più recente, il modo più semplice per farlo è la nuova funzione delete-duplicate-lines. Si noti che

  • questo funziona su una regione, non è un buffer, in modo da selezionare il testo desiderato prima
  • mantiene l'ordine relativo degli originali, uccidendo i duplicati

Ad esempio, se il ingresso è

test 
dup 
dup 
one 
two 
one 
three 
one 
test 
five 

M-x delete-duplicate-lines renderebbe

test 
dup 
one 
two 
three 
five 

Si ha la possibilità di cercare dall'indietro anteponendolo con l'argomento universale (C-u). Il risultato sarebbe quindi

dup 
two 
three 
one 
test 
five 

merito va a emacsredux.com.

Altre opzioni rotonda, che non danno abbastanza lo stesso risultato, disponibili tramite ESHELL:

  1. sort -u; non mantiene l'ordine relativo degli originali
  2. uniq; peggio ha bisogno di un suo input per essere ordinato
+0

'sort -u' potrebbe non essere un ordinamento stabile, ma' sort -u -s' è – Squidly

+0

Sì, è vero. Risolto ora! Anche eseguirlo da Eshell sembra essere una soluzione meno pulita che utilizza la funzione integrata. – legends2k

+0

@Squid Penso di aver dato l'ultimo commento senza verificare correttamente il tuo. Prova ad inserire i dati di input sia in 'sort -u' che in' sort -us', otterresti lo stesso risultato che non è lo stesso di 'delete-duplicate-lines'. Più precisamente, non stiamo parlando di un ordinamento stabile, il che significa che viene mantenuto l'ordine relativo di elementi identici. Dal momento che stiamo rimuovendo i duplicati, gli elementi identici sono comunque persi. 'delete-duplicate-lines' mantiene l'ordine degli originali e non i duplicati; quindi uno non sarebbe in grado di ottenere lo stesso risultato con 'sort'. – legends2k

Problemi correlati