感谢大家的帮助,我根据大家的建议又深入研究了一下,下面主要是我的一些记
录,在最后给出了一个新版本对 Elisp intro 11.4.4 的解法。
再次谢谢大家。
indentation issue
已经安装了 agreesive-indent-mode
来让缩进更好看。
lisp style
Always enable lexical scoping. This must be done on the first line as a file local variable.
Appendix D Tips and Conventions
dynamic array
感谢分享这个代码:
(catch 'finish
(let (result)
(while t
(if-let* ((start-point (search-forward "dfn{" nil t))
(end-point (search-forward "}" nil t)))
(push (buffer-substring-no-properties start-point end-point)
result)
(throw 'finish result)))))
-
catch 和 throw 的这个用法很好用。我进一步看了 Emacs Reference Manual:
The ‘throw’ need not appear lexically within the ‘catch’ that it jumps to. It can equally well be called from another function called within the ‘catch’. As long as the ‘throw’ takes place chronologically after entry to the ‘catch’, and chronologically before exit from it, it has access to that ‘catch’.
throw
还可以在写在别的函数中,只要 throw 在 catch 后执行。 以后可能会用上这样的方法。
-
关于 let
我在 Eintro 中看到 let
是这样说明的:
(let ((VARIABLE VALUE)
(VARIABLE VALUE)
...)
BODY...)
这里的能不能写成: (let result …
? 也就是去掉 result
的括号? 或者 result '())
?
-
关于 if-let*
这个用法很方便。在绑定局部变量的之后,返回真或假。如果真,则执行 (push …)
; 如果假,则 (throw …)
。
-
关于 search-forward
的传入参量: nil t
A value of nil means search to the end of the accessible portion of the buffer. Optional third argument, if t, means if fail just return nil (no error).
这个比我原来用 (point-max)
简洁多了。
整合成了一个新的函数
我把 @cireu 提供的方法,尝试将其整合成了一个新的函数。我把原来的函数搜索内容的循环代码:
(while (< 0 (how-many "dfn{" (point) (point-max)))
(copy-region-as-kill (search-forward "dfn{" (point-max))
(- (search-forward "}") 1))
(setq newCindex (concat "@cindex "
(substring-no-properties (nth 0 kill-ring)) "\n"))
用建议代码替换:
(catch 'finish
(let (result)
(while t
(if-let* ((start-point (search-forward "dfn{" nil t))
(end-point (search-forward "}" nil t)))
(push (buffer-substring-no-properties start-point end-point)
result)
(throw 'finish result)))
按照我的理解,这段函数提取了所有 @dfn{}
中的内容,然后将结果以 result
返回。
发现,不能如愿。
然后我从从 Elisp Manual 中找到一个小例子 ((elisp) Catch and Throw)
,稍微做了一点修改:
(defun foo-outer ()
(interactive)
(message
(catch 'foo
(foo-inner))))
(defun foo-inner ()
(let ((test-string "test-AAA"))
(throw 'foo test-string)))
;; M-x foo-outer
;; ⇒ test-AAA
也就是通过 catch
and throw
将 test-AAA
从 foo-inner
传给 foo-outer
。
之后,打算将下面的代码修改成可用执行函数:
(catch 'finish
(let (result)
(while t
(if-let* ((start-point (search-forward "dfn{" nil t))
(end-point (search-forward "}" nil t)))
(push (buffer-substring-no-properties start-point end-point)
result)
(throw 'finish result)))
这是我修改后的代码:
(defun return-result ()
(interactive)
(message
(catch 'finish
(collection-dfn-content))))
(defun collection-dfn-content ()
(catch 'finish
(let (result)
(while t
(if-let* ((start-point (search-forward "dfn{" nil t))
(end-point (search-forward "}" nil t)))
(push (buffer-substring-no-properties start-point end-point)
result)
(throw 'finish result))))))
在某个 *.texi buffer 的某个含有 @dfn{}
的段落内执行: M-x return-result
出现下面的错误:
return-result: Wrong type argument: stringp, ("\" (point) (point-max)))
(copy-region-as-kill (search-forward \"dfn{\" (point-max))
(- (search-forward \"}" "fixed}" "file}" "begining}" "paragraphindent}" "found ddd}" "write more}" "looks}" "make}" "second}" ...)
abuse “kill ring”
(with-temp-buffer
(url-insert-file-contents "https://raw.githubusercontent.com/emacs-mirror/emacs/master/doc/emacs/basic.texi")
(let ((dfns '()))
(goto-char (point-min))
(while (re-search-forward "@dfn{\\([^}]+\\)}" nil t)
(push (match-string 1) dfns))
dfns))
感谢你的代码,非常简单好用。几个从来没接触到的东西:
-
with-temp-buffer
-
url-insert-file-contents
用来分享代码片断非常好用。
-
dfns '()
: 对空 list 初始化
-
在搜索的时候大家都用这样方式: search-forward nil t
-
研究了这个正则: @dfn{\\([^}]+\\)}
-
学到了这个表达,也就是排除 “}”:
-
看到了这个章节 (elisp) Simple Match Data 才知道 subexpression 的用法。
我发现 @dfn{\\([^{]+\\)}
这个正则同样能达到目的,但是不知道为什么。
我自己的理解是 [^{]
在 subexpression 中剔除一个字符,这里我看到用了 ‘}’, 我自己用 '{'发现 也实现了相同的功能。
进一步,可能这是一个很技巧的东西。在 subexpression
为了,提取 {内容}
, 用到了这个 [^{]+
,请问这是普遍的做法么?
-
原来我一直在寻找的东西叫 (push)
更新
根据大家的建议,我把代码进行了一些修改,主要是避免滥用 kill-ring
(谢谢 @twlz0ne)。
(defun my-create-cindex ()
"Extract and update contents in @dfns{CONTENTS} in current
paragraph."
(interactive)
(my-delete-old-cindex)
(let ((beg (progn (save-excursion
(backward-paragraph) (point))))
(end (progn (save-excursion
(forward-paragraph) (point))))
(dfns '()))
(save-excursion
(save-restriction
(widen)
(narrow-to-region beg end)
(goto-char (point-min))
(while (re-search-forward "@dfn{\\([^}]+\\)}" nil t)
(push (match-string 1) dfns))
(backward-paragraph)
(newline)
(print-elements-of-list dfns)))))
(defun my-delete-old-cindex ()
"Delete old cindex before the current paragraph."
(interactive)
(save-excursion
(save-restriction
(let ((beg (progn (save-excursion
(save-restriction
(widen)
(backward-paragraph 2)
(forward-paragraph)
(point)))))
(end (progn (save-excursion
(save-restriction
(widen)
(backward-paragraph) (point))))))
(flush-lines "@cindex" beg end)))))
(defun print-elements-of-list (list)
"Print each element of LIST on a line of its own."
(while list
(insert-before-markers
(concat (concat "@cindex "
(format "%s" (car list)))) "\n")
(setq list (cdr list))))