【问题标题】:Why does this elisp function to grab text from buffer not work为什么这个从缓冲区中获取文本的 elisp 函数不起作用
【发布时间】:2013-04-05 03:08:18
【问题描述】:

我有一些这样的文字:

qwerty\tberty 
merty\tserty 

我想抓取制表符和行尾之间的文本 berty。然后显示它工作到缓冲区的末尾并在那里插入文本。

但是这段代码不起作用。有什么想法为什么不呢?

(defun do-test ()
  "tester"
  (interactive)
  (goto-char (point-min))
  (if (search-forward "qwerty" nil t)
     (delete-char 1) ;;delete tab
     (setq myStr (buffer-substring point end-of-line)) ;add text to variable
     ;goto end of buffer and insert text as demonstration it works
     (goto-char (point-max))
     (insert(myStr))
  )
)

编辑:

抱歉,剪切和粘贴错误。应该是:

(if (search-forward "qwerty" nil t)

【问题讨论】:

  • “选项名称”是做什么用的?另外,请提供输入缓冲区内容和相关的所需输出缓冲区内容以了解问题所在。
  • @NicolasDudebout 抱歉,已删除选项名称 - 应该是 qwerty。示例缓冲区是上面的文本。

标签: emacs elisp


【解决方案1】:

你的代码有很多问题:

  1. if 采用第一个参数,如果测试结果为阳性,则执行该参数;否则,所有剩余的参数都将被执行(就像大多数情况下的 else 子句一样) 命令式语言)。您可以将所有表达式分组到 progn 表单中,也可以使用 when 表单,它采用任意数量的表达式来评估条件是否为真,并且没有 else 子句。

    李>
  2. pointline-end-position 是函数,这意味着您必须调用它们才能获取值:例如 (point)

  3. 另一方面,myStr 是一个变量,这意味着你可以直接插入它的值(不能像函数一样调用它)

  4. 如果要保持原始缓冲区不变,应将指针向前移动 1 个字符,而不是删除 TAB。这可以使用forward-char 命令完成。

考虑到所有这些,这是您的函数的修改版本。另外,我将“选项名称”更改为“qwerty”以匹配您的示例。

(defun do-test ()
  "tester"
  (interactive)
  (goto-char (point-min))
  (when (search-forward "qwerty" nil t)
      (forward-char 1) ;;skip tab
      ;store text in variable `myStr'
      (setq myStr (buffer-substring (point) (line-end-position)))
      ;goto end of buffer and insert text as demonstration it works
      (goto-char (point-max))
      (insert myStr)))

请注意,使用正则表达式可能是实现目标的更好方法:

(defun do-test ()
  (interactive)
  (goto-char (point-min))
  (when (re-search-forward "qwerty\t\\(.*\\)")
    (goto-char (point-max))
    (insert (match-string 1))))

【讨论】:

  • 由于某种原因,使用正则表达式的示例有效,但第一个示例无效。第一个示例给出错误:错误的类型参数:整数或标记-p,nil。有什么想法吗?
  • 还有一个问题。正则表达式在没有两个 \\ 对的情况下工作。 \\ 的目的是什么
  • 您会发现大量关于 emacs 正则表达式语法的文档,例如在 emacs manual 中。简而言之,\(...\) 在正则表达式中包含一个组,这意味着稍后可以检索在此构造中匹配的子字符串,在本例中使用(match-string 1)。由于这里的正则表达式是一个elisp字符串,所以需要对反斜杠进行转义,从而导致"\\(...\\)"构造。
  • 我不明白为什么第一个示例不起作用。您可以使用M-x toggle-debug-on-error 跟踪错误的确切位置:此后,每次抛出错误时都会激活调试器,向您显示哪个函数没有得到预期的参数。
【解决方案2】:

除了@Francesco 的回答,我认为逻辑非常脆弱,它会影响编辑器的全局状态。您可以考虑按照以下思路将解析提取到纯函数中:

(defun extract-matches (str)
  "Extract the last tab-separated value of each line in STR."
  (mapcar (lambda (s) (car (last (split-string s "\t"))))
          (remove-if-not (lambda (s) (string-match-p "\t" s))
                         (split-string str "\n"))))

(defun extract-eol-tsv ()
  "For each line in the buffer, extract the last tab-delimited
phrase and insert it at the end of the buffer."
  (interactive)
  (save-excursion
    (goto-char (point-max))
    (dolist (m (extract-matches (buffer-string))) 
      (insert (format "%s\n" m)))

使用纯函数有助于保持有趣的逻辑可测试 - 现在,您无需修改​​缓冲区即可验证 finnicky 解析内容是否有效。

【讨论】:

  • 是的,我需要学习如何使用 lisp 成语进行编程,而不是以命令的方式将 lisp 函数组合在一起。
  • 当您需要进行严格的文本转换时,它有助于使用临时缓冲区,因为许多 emacs 的内置字符串函数会修改缓冲区和编辑器状态。查看with-temp-buffersave-match-datasave-excursion 的文档。 :)
猜你喜欢
  • 2014-04-02
  • 1970-01-01
  • 2016-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-14
相关资源
最近更新 更多