Обработка текста с elisp

Так как я преобразовал в церковь Emacs, я пытался сделать все из него, и я задавался вопросом, как сделать некоторую обработку текста быстро и эффективно с ним.

Как пример, давайте возьмем этот список, который я редактировал несколько минут назад на org-режиме.

** Diego: b QI
** bruno-gil: b QI
** Koma: jo
** um: rsrs pr0n
** FelipeAugusto: esp
** GustavoPupo: pinto tr etc
** GP: lit gtk
** Alan: jo mil pc
** Jost: b hq jo 1997
** Herbert: b rsrs pr0n
** Andre: maia mil pseudo
** Rodrigo: c
** caue: b rsrs 7arte pseudo
** kenny: cri gif
** daniel: gtk mu pr0n rsrs b
** tony: an 1997 esp
** Vitor: b jo mimimi
** raphael: b rpg 7arte
** Luca: b lit gnu pc prog mmu 7arte 1997
** LZZ: an qt
** William: b an jo pc 1997
** Epic: gtk
** Aldo: b pseudo pol mil fur
** GustavoKyon: an gtk
** CarlosIsaksen : an hq jo 7arte gtk 1997
** Peter: pseudo pol mil est 1997 gtk lit lang
** leandro: b jo cb
** frederico: 7arte lit gtk
** rol: b an pseudo mimimi 7arte
** mathias: jo lit
** henrique: 1997 h gtk qt
** eumané: an qt
** walrus: cri de
** FilipePinheiro: lit pseudo
** Igor: pseudo b
** Erick: b jo rpg q 1997 gtk
** Gabriel: pr0n rsrs qt
** george: clo mimimi
** anão: hq jo 1997 rsrs clô b
** jeff: 7arte gtk
** davidatenas:  an 7arte 1997 esp qt
** HHahaah: b 
** Eduardo: b

Это - список имен, связанных с тегами, и я хочу получить список тегов, связанных с именами.

В ударе я сначала повторил бы с одинарными кавычками все это вставляемое и затем передал бы его по каналу к awk, цикличному выполнению по каждой строке и добавляющий каждого ее части к правильной временной переменной и затем смешивающий с ним, пока он не похож, я хочу.

echo '** Diego: b QI
** bruno-gil: b QI
** Koma: jo
** um: rsrs pr0n
** FelipeAugusto: esp
** GustavoPupo: pinto, tr etc
** GP: lit gtk
** Alan: jo mil pc
** Jost: b hq jo 1997
** Herbert: b rsrs pr0n
** Andre: maia mil pseudo
** Rodrigo: c
** caue: b rsrs 7arte pseudo
** kenny: cri gif
** daniel: gtk mu pr0n rsrs b
** tony: an 1997 esp
** Vitor: b jo mimimi
** raphael: b rpg 7arte
** Luca: b lit gnu pc prog mmu 7arte 1997
** LZZ: an qt
** William: b an jo pc 1997
** Epic: gtk
** Aldo: b pseudo pol mil fur
** GustavoKyon: an gtk
** CarlosIsaksen : an hq jo 7arte gtk 1997
** Peter: pseudo pol mil est 1997 gtk lit lang
** leandro: b jo cb
** frederico: 7arte lit gtk
** rol: b an pseudo mimimi 7arte
** mathias: jo lit
** henrique: 1997 h gtk qt
** eumané: an qt
** walrus: cri de
** FilipePinheiro: lit pseudo
** Igor: pseudo b
** Erick: b jo rpg q 1997 gtk
** Gabriel: pr0n rsrs qt
** george: clo mimimi
** anão: hq jo 1997 rsrs clô b
** jeff: 7arte gtk
** davidatenas:  an 7arte 1997 esp qt
** HHahaah: b
** Eduardo: b
' | awk '{sub(":","");for (i=3;i<=NF;i++) members[$i] = members[$i] " " $2}; END{for (j in members) print j ": " members[j]}' | sort

... и TA-DA! Ожидаемый вывод меньше чем за 2 минуты, сделанные интуитивным и возрастающим способом. Можно ли показать мне, как сделать что-то вроде этого в elisp, предпочтительно в буфере emacs, с элегантностью и простотой?

Спасибо!

6
задан konr 3 January 2010 в 08:01
поделиться

5 ответов

Чтобы предоставить конкретный пример для освещения того, что другие люди комментируют: для реализации Z-машинного интерпретатора следует использовать три различных стека. Стек вызовов и несколько различных типов стеков объектов. (Конкретные требования можно найти здесь. ) Обратите внимание, что, как и все эти примеры, хотя использование стека не является строго обязательным , это очевидный выбор.

Стек вызовов сохраняет трек рекурсивных вызовов подпрограмм, в то время как стек объектов используется для трека внутренних предметов.

-121--3048022-

Я использовал их для трека действий отмены и повторного выполнения.

Я использую интерфейс примерно так:

interface ICommand
{
    void Execute();
    void Undo();
    string Description { get; }
}

Undo и Redo имеют тип Stack < ICommand > . Тогда я создаю конкретный класс для данного действия. В конструкторе класса я передаю любую информацию, за которую нужно держаться. Выполнение выполняет действие первоначально, а также повторно выполняет его; Отменить , очевидно. Он работает следующим образом:

  • Отменить действие: Открыть стек отмены и добавить в стек повтора.
  • Повторить действие отмены: Снова откройте стек Redo и добавьте его в стек Undo.
  • Выполните новое действие: Добавьте в стек Undo и очистите стек Redo (поскольку состояние больше не является согласованным).

Я обнаружил, что вы должны позаботиться о том, чтобы вы действительно отменили то, что было сделано. Например, предположим, что у вас есть пользовательский интерфейс с двумя списками, и в каждом из них по пять предметы. Ваше действие может заключаться в том, чтобы нажать кнопку, чтобы переместить все в левом списке в правый список (так что теперь он имеет десять, а левый список имеет ноль).

Действие отмены не для перемещения всего назад; действие отмены состоит в том, чтобы вернуть назад только пять, которые вы фактически перенесли, и оставить остальные.

-121--3048008-

Это моя вторая попытка. Я написал небольшой макрос и некоторые функции, чтобы справиться с такими данными.

(defun better-numberp (s)
  (string-match "^ *[0-9.,]* *$" s))

(defmacro awk-like (&rest args)
  (let ((arg (car (last args)))
        (calls (mapcar #'(lambda (l)
                           (cond
                            ((numberp (first l)) (cons `(lambda (f) (equal %r ,(first l))) (rest l)))
                            ((stringp (first l)) (cons `(lambda (f) (string-match ,(first l) %)) (rest l)))
                            (t l)))
                       (butlast args))))
    `(mapcar #'(lambda (%%)
                 (let ((%r 0))
                   (mapcar
                    #'(lambda (l)
                        (setq %r (1+ %r))
                        (let ((% l))
                          (dolist (tipo ',calls)
                            (progn
                              (setq % (cond
                                       ((funcall (first tipo) %) (eval (cadr tipo))) (t %)))
                              (set (intern (format "%%%d" %r)) %))) %)) %%)))
             (mapcar #'(lambda (y) (split-string y " " t))
                     (split-string ,arg "\n" t)))))

(defun hash-to-list (hashtable)
  "Return a list that represent the hashtable."
  (let (mylist)
    (maphash (lambda (kk vv) (setq mylist (cons (list kk vv) mylist))) hashtable)
    mylist
    )
  )

(defun append-hash (key value hashtable)
  (let ((current (gethash key hashtable)))
    (puthash key 
             (cond
              ((null current) (list value))
              ((listp current) (cons value current))
              (t current)) 
             hashtable)))

(let ((foohash (make-hash-table :test 'equal)))
  (awk-like
   (2 (replace-regexp-in-string ":" "" %))
   ((lambda (f) (> %r 2))  (append-hash % %2 foohash))
   "** Diego: b QI
** bruno-gil: b QI
** Koma: jo
** um: rsrs pr0n
** FelipeAugusto: esp
** GustavoPupo: pinto tr etc
** GP: lit gtk
** Alan: jo mil pc
** Jost: b hq jo 1997
** Herbert: b rsrs pr0n
** Andre: maia mil pseudo
** Rodrigo: c
** caue: b rsrs 7arte pseudo
** kenny: cri gif
** daniel: gtk mu pr0n rsrs b
** tony: an 1997 esp
** Vitor: b jo mimimi
** raphael: b rpg 7arte
** Luca: b lit gnu pc prog mmu 7arte 1997
** LZZ: an qt
** William: b an jo pc 1997
** Epic: gtk
** Aldo: b pseudo pol mil fur
** GustavoKyon: an gtk
** CarlosIsaksen: an hq jo 7arte gtk 1997
** Peter: pseudo pol mil est 1997 gtk lit lang
** leandro: b jo cb
** frederico: 7arte lit gtk
** rol: b an pseudo mimimi 7arte
** mathias: jo lit
** henrique: 1997 h gtk qt
** eumané: an qt
** walrus: cri de
** FilipePinheiro: lit pseudo
** Igor: pseudo b
** Erick: b jo rpg q 1997 gtk
** Gabriel: pr0n rsrs qt
** george: clo mimimi
** anão: hq jo 1997 rsrs clô b
** jeff: 7arte gtk
** davidatenas:  an 7arte 1997 esp qt
** HHahaah: b
** Eduardo: b
")
  (hash-to-list foohash))
0
ответ дан 8 December 2019 в 13:00
поделиться

Первое, что я бы сделал, это воспользовался поддержкой тегов в org-режиме . Вместо

** Diego: b QI

У вас будет

** Diego                          :b:QI:

Который org-режим распознает как тэги "b" и "QI".

Для преобразования вашего текущего формата в стандартный org-режим , вы можете использовать следующее (предполагая, что буфер с вашим исходным текстом называется "asdf")

(with-current-buffer "asdf"
  (beginning-of-buffer)
  (replace-string " " ":")
  (beginning-of-buffer)
  (replace-string "**:" "** ")
  (beginning-of-buffer)
  (replace-string "::" " :")
  (beginning-of-buffer)
  (replace-string "\n" ":\n")
  (org-set-tags-command t t))

Это некрасиво и неэффективно, но это делает работу.

После этого вы можете использовать следующее для создания буфера, который имеет формат который вы хотели получить от скрипта оболочки:

(let ((results (get-buffer-create "results"))
      tags)
  (with-current-buffer "asdf"
    (beginning-of-buffer)
    (while (org-on-heading-p)
      (mapc '(lambda (item) (when item (add-to-list 'tags item))) (org-get-local-tags))
      (outline-next-visible-heading 1)))
  (setq tags (sort tags 'string<))
  (with-current-buffer results
    (erase-buffer)
    (mapc '(lambda (item)
             (insert (format "%s: %s\n"
                             item
                             (with-current-buffer "asdf"
                               (org-map-entries '(substring-no-properties (org-get-heading t)) item)))))
          tags)
    (beginning-of-buffer)
    (replace-regexp "[()]" "")))

Это помещает результаты в буфер, называемый "results", создавая его, если он не уже существуют. В основном, он собирает все теги в буфере "asdf", сортируя их, затем перебирая каждую метку и ищет каждый заголовок с помощью который пометит "asdf" и вставит его в "результаты".

С небольшим очищением, это может быть сделано в функцию; в основном, просто заменив "asdf" и "results" аргументами. Если вы хотите, чтобы это было сделано, я могу сделать что.

7
ответ дан 8 December 2019 в 13:00
поделиться

Существует функция shell-command-on-region, которая в основном делает то, что она говорит. Вы можете выделить регион, сделать M-|, ввести имя команды оболочки, и данные будут переданы в эту команду. Дайте ему аргумент, и регион будет заменен результатом команды.

Для тривиального примера выделите регион, наберите 'C-u 0 M-| wc' (controll-u, zero, meta-pipe, а затем 'wc'), и регион будет заменен количеством символов, слов и строк этого региона.

Другое, что вы можете сделать - это понять, как управлять одной строкой, сделать из нее макрос, а затем запустить макрос несколько раз. Например, 'C-x ( C-s foo C-g bar C-x )' будет искать слово "foo", затем набирать слово "bar", меняя его на "foobar". Затем можно один раз сделать 'C-u C-x e', который будет постоянно запускать макрос до тех пор, пока не будет найдено больше никаких вхождений "foo".

5
ответ дан 8 December 2019 в 13:00
поделиться

Предыдущие альтернативы интересны, но я не думаю, что они отражают "как бы я сделал это в Emacs как недавно обращенный" аспект вопроса. Я подозреваю, что кто-то, изучая Emacs, может начать с чего-то вроде:

(defun create-tags-to-name (buffer-name)
  "Create a buffer filled with lines containg `** TAG:
LIST-OF-NAMES' by transposing lines in the region matching the
format `** NAME: LIST-OF-TAGS' where the list items are white
space separated."
  (interactive)
  (let ((buf (get-buffer-create buffer-name))
    (tag-to-name-list (list))
    name tags element)
    ;; Clear the destination buffer
    (with-current-buffer buf
      (erase-buffer))
    ;; Build the list of tag to name associations.
    (while (re-search-forward "^** \\([-a-zA-Z0-9 ]+\\):\\(.+\\)$" (point-max) t)
      (setq name (buffer-substring (match-beginning 1) (match-end 1))
        tags (split-string (buffer-substring (match-beginning 2) (match-end 2))))
      ;; For each tag add the name to the tag's name list
      (while tags
    (let ((tag (car tags)))
      (setq element (assoc tag tag-to-name-list)
        tags (cdr tags))
      (if element
          (setcdr element (append (list name) (cdr element)))
        (setq tag-to-name-list (append (list (cons tag (list name))) tag-to-name-list))))))
    ;; Dump the associations to the target buffer
    (with-current-buffer buf
      (while tag-to-name-list
    (setq element (car tag-to-name-list)
          tag-to-name-list (cdr tag-to-name-list))
    (insert (concat "** " (car element) ":"))
    (let ((tag-list (cdr element)))
      (while tag-list
        (insert " " (car tag-list))
        (setq tag-list (cdr tag-list))))
    (insert "\n")))))
1
ответ дан 8 December 2019 в 13:00
поделиться
- 3853891-

Хорошо, вот моя первая попытка ELISP:

  1. Я начинаю буфер с режимами ELISP и Paredit, открыть двойные кавычки и вставьте текст
  2. Я связываю его с символом Используя Пусть
(let ((foobar "** Diego: b QI
** bruno-gil: b QI
** Koma: jo
** um: rsrs pr0n
** FelipeAugusto: esp
** GustavoPupo: pinto, tr etc
** GP: lit gtk
** Alan: jo mil pc
** Jost: b hq jo 1997
** Herbert: b rsrs pr0n
** Andre: maia mil pseudo
** Rodrigo: c
** caue: b rsrs 7arte pseudo
** kenny: cri gif
** daniel: gtk mu pr0n rsrs b
** tony: an 1997 esp
** Vitor: b jo mimimi
** raphael: b rpg 7arte
** Luca: b lit gnu pc prog mmu 7arte 1997
** LZZ: an qt
** William: b an jo pc 1997
** Epic: gtk
** Aldo: b pseudo pol mil fur
** GustavoKyon: an gtk
** CarlosIsaksen : an hq jo 7arte gtk 1997
** Peter: pseudo pol mil est 1997 gtk lit lang
** leandro: b jo cb
** frederico: 7arte lit gtk
** rol: b an pseudo mimimi 7arte
** mathias: jo lit
** henrique: 1997 h gtk qt
** eumané: an qt
** walrus: cri de
** FilipePinheiro: lit pseudo
** Igor: pseudo b
** Erick: b jo rpg q 1997 gtk
** Gabriel: pr0n rsrs qt
** george: clo mimimi
** anão: hq jo 1997 rsrs clô b
** jeff: 7arte gtk
** davidatenas:  an 7arte 1997 esp qt
** HHahaah: b 
** Eduardo: b 
"))
  foobar)

Теперь я меняю Foobar на что-то фантастическое.

  1. Сначала я удаляю символы с регулярным выражением и разделите текст в струнах, используя (Split-String)
  2. , то я делаю mapcar, чтобы превратить каждую строку в список слов
(mapcar #'(lambda (y) (split-string y " " t)) (split-string (replace-regexp-in-string "[:\*]" "" foobar) "\n" t))
  1. , то я создаю Hashmap и связывают его с Temphash ( (Temphash (Make-hash-Table: Test 'Care)) )
  2. , а затем я цикл в вложенные списки, чтобы добавить элементы в хэш-таблицу. Я думаю, что я не должен делать нефункциональное программирование с MapCar, но никто не смотрит;)
(mapcar #'(lambda (l)
              (mapcar #'(lambda (m) (puthash m (format "%s %s" (car l) (let ((tempel (gethash m temphash)))
                                                            (if tempel tempel ""))) temphash)) (rest l)))
          (mapcar #'(lambda (y) (split-string y " " t)) (split-string (replace-regexp-in-string "[:\*]" "" foobar) "\n" t))) 
  1. Наконец, я извлекаю элементы из хеш-таблица в другой набор вложенных списков с удобной функцией, украденной из веб-страницы Xah Lee ,
  2. И, наконец, я симпатию печатаю его другому буферу с MX PP-Eval-Sexp

Это маленькое ума для разума, особенно двойной mapcar, но это работает. Вот полный "код":

;; Stolen from Xah Lee's page


(defun hash-to-list (hashtable)
  "Return a list that represent the hashtable."
  (let (mylist)
    (maphash (lambda (kk vv) (setq mylist (cons (list kk vv) mylist))) hashtable)
    mylist
  )
)

;; Code

(let ((foobar "** Diego: b QI
** bruno-gil: b QI
** Koma: jo
** um: rsrs pr0n
** FelipeAugusto: esp
** GustavoPupo: pinto, tr etc
** GP: lit gtk
** Alan: jo mil pc
** Jost: b hq jo 1997
** Herbert: b rsrs pr0n
** Andre: maia mil pseudo
** Rodrigo: c
** caue: b rsrs 7arte pseudo
** kenny: cri gif
** daniel: gtk mu pr0n rsrs b
** tony: an 1997 esp
** Vitor: b jo mimimi
** raphael: b rpg 7arte
** Luca: b lit gnu pc prog mmu 7arte 1997
** LZZ: an qt
** William: b an jo pc 1997
** Epic: gtk
** Aldo: b pseudo pol mil fur
** GustavoKyon: an gtk
** CarlosIsaksen : an hq jo 7arte gtk 1997
** Peter: pseudo pol mil est 1997 gtk lit lang
** leandro: b jo cb
** frederico: 7arte lit gtk
** rol: b an pseudo mimimi 7arte
** mathias: jo lit
** henrique: 1997 h gtk qt
** eumané: an qt
** walrus: cri de
** FilipePinheiro: lit pseudo
** Igor: pseudo b
** Erick: b jo rpg q 1997 gtk
** Gabriel: pr0n rsrs qt
** george: clo mimimi
** anão: hq jo 1997 rsrs clô b
** jeff: 7arte gtk
** davidatenas:  an 7arte 1997 esp qt
** HHahaah: b 
** Eduardo: b 
")
      (temphash  (make-hash-table :test 'equal)))
  (mapcar #'(lambda (l)
              (mapcar #'(lambda (m) (puthash m (format "%s %s" (car l) (let ((tempel (gethash m temphash)))
                                                            (if tempel tempel ""))) temphash)) (rest l)))
          (mapcar #'(lambda (y) (split-string y " " t)) (split-string (replace-regexp-in-string "[:\*]" "" foobar) "\n" t)))
  (hash-to-list temphash)) 

и вот вывод:

(("clô" "anão ")
 ("clo" "george ")
 ("q" "Erick ")
 ("de" "walrus ")
 ("h" "henrique ")
 ("cb" "leandro ")
 ("lang" "Peter ")
 ("est" "Peter ")
 ("fur" "Aldo ")
 ("pol" "Peter Aldo ")
 ("qt" "davidatenas Gabriel eumané henrique LZZ ")
 ("mmu" "Luca ")
 ("prog" "Luca ")
 ("gnu" "Luca ")
 ("rpg" "Erick raphael ")
 ("mimimi" "george rol Vitor ")
 ("an" "davidatenas eumané rol CarlosIsaksen GustavoKyon William LZZ tony ")
 ("mu" "daniel ")
 ("gif" "kenny ")
 ("cri" "walrus kenny ")
 ("7arte" "davidatenas jeff rol frederico CarlosIsaksen Luca raphael caue ")
 ("c" "Rodrigo ")
 ("pseudo" "Igor FilipePinheiro rol Peter Aldo caue Andre ")
 ("maia" "Andre ")
 ("1997" "davidatenas anão Erick henrique Peter CarlosIsaksen William Luca tony Jost ")
 ("hq" "anão CarlosIsaksen Jost ")
 ("pc" "William Luca Alan ")
 ("mil" "Peter Aldo Andre Alan ")
 ("gtk" "jeff Erick henrique frederico Peter CarlosIsaksen GustavoKyon Epic daniel GP ")
 ("lit" "FilipePinheiro mathias frederico Peter Luca GP ")
 ("etc" "GustavoPupo ")
 ("tr" "GustavoPupo ")
 ("pinto," "GustavoPupo ")
 ("esp" "davidatenas tony FelipeAugusto ")
 ("pr0n" "Gabriel daniel Herbert um ")
 ("rsrs" "anão Gabriel daniel caue Herbert um ")
 ("jo" "anão Erick mathias leandro CarlosIsaksen William Vitor Jost Alan Koma ")
 ("QI" "bruno-gil Diego ")
 ("b" "Eduardo HHahaah anão Erick Igor rol leandro Aldo William Luca raphael Vitor daniel caue Herbert Jost bruno-gil Diego "))
3
ответ дан 8 December 2019 в 13:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: