28

たくさんの行があるテキストがありますが、私の質問はemacsの繰り返し行を削除する方法ですか?外部utilsなしでemacsまたはelispパッケージでコマンドを使用する。

例えば:

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

3行目を削除するには(1行目と同じ)

this is line a
this is line b
4

5 に答える 5

19

次のコードを .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))))))

使用法:

M-x uniq-lines
于 2012-10-24T10:03:45.710 に答える
13

Linux では、リージョンを選択し、次のように入力します

M-| uniq <RETURN>

重複のない結果は新しいバッファにあります。

于 2015-02-07T16:00:50.510 に答える
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))))))

別の方法:

  • 一致を保存するために元に戻す履歴を使用しません。
  • 一般的には高速になります (ただし、究極の速度を求める場合は、プレフィックス ツリーを構築してください)。
  • 以前のすべての改行文字を置き換える効果があります\n(UNIX スタイル)。状況に応じて、どちらが有利にも不利にもなる可能性があります。
  • split-string正規表現の代わりに文字を受け入れるように再実装すると、少し改善 (高速化) できます。

多少長くなりますが、おそらくもう少し効率的なバリアントです。

(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))))))
于 2012-10-24T11:09:49.807 に答える