如何插入ELisp列表的中间?

时间:2013-12-29 01:43:22

标签: list emacs lisp elisp

我将以下数据结构作为ELisp变量(ispell-tex-skip-alists):

((("---" ispell-tex-arg-end 2)
  ("---" ispell-tex-arg-end)
  ("---" ispell-tex-arg-end)
  ("---" ispell-tex-arg-end)
  ("---" ispell-tex-arg-end 0)
  ("---" ispell-tex-arg-end)
  ("---" . "---"))
 (("---" ispell-tex-arg-end 0)
  ("---" ispell-tex-arg-end 2)
  ("env1" . "endenv1")
  ("env2" . "endenv2")))

我可以使用cddadr将我需要的列表部分隔离开来,   但我需要在此列表中添加一个元素:

((("---" ispell-tex-arg-end 2)
  ("---" ispell-tex-arg-end)
  ("---" ispell-tex-arg-end)
  ("---" ispell-tex-arg-end)
  ("---" ispell-tex-arg-end 0)
  ("---" ispell-tex-arg-end)
  ("---" . "---"))
 (("---" ispell-tex-arg-end 0)
  ("---" ispell-tex-arg-end 2)
  ("env1" . "endenv1")
  ("env2" . "endenv2")
  ("env3" . "endenv3")))

我尝试了add-to-list,但显然我需要cddadr部分的符号名称(我可以在技术上优化到cadradd-to-list工作

我如何实现我需要的结果?


最佳尝试:

(defun LaTeX-ispell-skip-environment (env &optional star)
  (let ((start (concat "%s" (if star "\\*?")))
    (end   (concat "\\\\end[    \n]*{[  \n]*%s" (if star "\\*?") "[     \n]*}")))
    (let ((env-list (cddadr ispell-tex-skip-alists)))
      (setcdr (last env-list)
          (cons (format start env)
            (format end env))))))

2 个答案:

答案 0 :(得分:1)

我认为你的方法中缺少list

(defun LaTeX-ispell-skip-environment (env &optional star)
  (let ((start (concat "%s" (if star "\\*?")))
    (end   (concat "\\\\end[    \n]*{[  \n]*%s" (if star "\\*?") "[     \n]*}")))
    (let ((env-list (cddadr ispell-tex-skip-alists)))
      (setcdr (last env-list)
              (list 
               (cons (format start env)
                     (format end env)))))))

在您的版本中,相关列表的结构会发生变化。在修改之前,它是一个conses列表。修改后,它是一个混合列表。大多数条目是conses但最后一个car是一个字符串,最后一个cdr也是一个字符串。

setcdrlast之外,您可以使用nconc

(defun LaTeX-ispell-skip-environment (env &optional star)
  (let ((start (concat "%s" (if star "\\*?")))
    (end   (concat "\\\\end[    \n]*{[  \n]*%s" (if star "\\*?") "[     \n]*}")))
    (let ((env-list (cddadr ispell-tex-skip-alists)))
      (nconc env-list
             (list 
              (cons (format start env)
                    (format end env)))))))

测试

接下来是一项测试。为了与原始发布中的所需结果进行比较,我将"\\\\end[ \n]*{[ \n]*%s"替换为"end%s",将"[ \n]*}"替换为""中的LaTeX-ispell-skip-environment。在progn结束时,(LaTeX-ispell-skip-environment "env3")的结果将使用equal针对所需结果进行测试。测试返回t

(progn
  (defun LaTeX-ispell-skip-environment (env &optional star)
    (let ((start (concat "%s" (if star "\\*?")))
      (end   (concat "end%s" (if star "\\*?") "")))
      (let ((env-list (cddadr ispell-tex-skip-alists)))
    (setcdr (last env-list)
        (list 
         (cons (format start env)
               (format end env)))))))

  (setq ispell-tex-skip-alists
    '((("---" ispell-tex-arg-end 2)
       ("---" ispell-tex-arg-end)
       ("---" ispell-tex-arg-end)
       ("---" ispell-tex-arg-end)
       ("---" ispell-tex-arg-end 0)
       ("---" ispell-tex-arg-end)
       ("---" . "---"))
      (("---" ispell-tex-arg-end 0)
       ("---" ispell-tex-arg-end 2)
       ("env1" . "endenv1")
       ("env2" . "endenv2"))))

  (LaTeX-ispell-skip-environment "env3")

  (equal ispell-tex-skip-alists
     '((("---" ispell-tex-arg-end 2)
        ("---" ispell-tex-arg-end)
        ("---" ispell-tex-arg-end)
        ("---" ispell-tex-arg-end)
        ("---" ispell-tex-arg-end 0)
        ("---" ispell-tex-arg-end)
        ("---" . "---"))
       (("---" ispell-tex-arg-end 0)
        ("---" ispell-tex-arg-end 2)
        ("env1" . "endenv1")
        ("env2" . "endenv2")
        ("env3" . "endenv3")))))

答案 1 :(得分:1)

为了更笼统地回答标题中的问题,这里有一个函数,它在列表的第 n 个位置插入一个元素:

(defun insert-into-list (list el n)
  "Insert into list LIST an element EL at index N.

If N is 0, EL is inserted before the first element.

The resulting list is returned.  As the list contents is mutated
in-place, the old list reference does not remain valid."
  (let* ((padded-list (cons nil list))
         (c (nthcdr n padded-list)))
    (setcdr c (cons el (cdr c)))
    (cdr padded-list)))