Подтвердить что ты не робот

Как удалить строки повтора в emacs

У меня есть текст с большим количеством строк, мой вопрос в том, как удалить строки повтора в emacs? используя команду в emacs или elisp-пакетах без внешних utils.

например:

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

чтобы удалить третью строку (то же, что и первая строка)

this is line a
this is line b
4b9b3361

Ответ 1

Поместите этот код в ваш .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

Ответ 2

Если у вас есть Emacs 24.4 или новее, самым чистым способом сделать это будет новая функция delete-duplicate-lines. Обратите внимание, что

  • это работает в области, а не в буфере, поэтому сначала выберите нужный текст.
  • он поддерживает относительный порядок оригиналов, убивая дубликаты

Например, если ваш вход

test
dup
dup
one
two
one
three
one
test
five

M-x delete-duplicate-lines сделает его

test
dup
one
two
three
five

У вас есть возможность поиска с обратной стороны путем префикса его универсальным аргументом (C-u). Тогда результатом будет

dup
two
three
one
test
five

Кредит переходит на emacsredux.com.

Другие варианты кругового обзора, не дающие совершенно одинакового результата, доступные через Eshell:

  • sort -u; не поддерживает относительный порядок оригиналов
  • uniq; хуже, он нуждается в сортировке своего ввода.

Ответ 3

В linux выберите область и введите

M-| uniq <RETURN>

Результат без дубликатов в новом буфере.

Ответ 4

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