Emacs 为什么从缓冲区抓取文本的elisp函数不起作用

Emacs 为什么从缓冲区抓取文本的elisp函数不起作用,emacs,elisp,Emacs,Elisp,我有一些这样的文字: qwerty\tberty merty\tserty 我想抓住制表符和行尾之间的文本berty。然后,为了显示它的工作状态,转到缓冲区的末尾并在那里插入文本 但是这个代码不起作用。有什么想法吗 (defun do-test () "tester" (interactive) (goto-char (point-min)) (if (search-forward "qwerty" nil t) (delete-char 1) ;;delete

我有一些这样的文字:

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))
  )
)
编辑:

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


(如果(向前搜索“qwerty”nil t)

代码中存在许多问题:

  • 如果
    接受第一个参数,该参数在测试为正时执行;否则将执行所有剩余的参数(如大多数 命令式语言)。您可以将所有表达式分组为
    progn
    形式,也可以使用
    when
    形式,该形式使用任意数量的表达式来计算条件是否为真,以及no
    else
    子句

  • 行结束位置
    是函数,这意味着您必须调用它们才能获取值:例如
    (点)

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

  • 如果要保持原始缓冲区的完整性,应将点向前移动1个字符,而不是删除选项卡。这可以使用
    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))))
    

    您的代码中存在许多问题:

  • 如果
    接受第一个参数,该参数在测试为正时执行;否则将执行所有剩余的参数(如大多数 命令式语言)。您可以将所有表达式分组为
    progn
    形式,也可以使用
    when
    形式,该形式使用任意数量的表达式来计算条件是否为真,以及no
    else
    子句

  • 行结束位置
    是函数,这意味着您必须调用它们才能获取值:例如
    (点)

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

  • 如果要保持原始缓冲区的完整性,应将点向前移动1个字符,而不是删除选项卡。这可以使用
    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))))
    

    除了@弗朗西斯科的回答之外,我认为逻辑是相当脆弱的,它影响编辑器的全局状态。您可以考虑将解析提取成纯函数,沿着这些线:

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

    使用纯函数有助于保持有趣的逻辑可测试性——现在,您可以在不修改缓冲区的情况下验证Frimyy解析工具的工作。

    除了@弗朗西斯科的回答之外,我认为逻辑是相当脆弱的,它会影响编辑器的全局状态。黑塞线:

    (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解析功能是否正常工作。

    什么是“选项名称”用于?另外,请提供输入缓冲区内容和相关的所需输出缓冲区内容,以了解问题所在。@NicolasDudebout抱歉,删除的选项名称-应为qwerty。示例缓冲区是上面的文本。什么是“选项名称”用于?此外,请提供输入缓冲区内容和相关的所需输出缓冲区内容,以了解问题所在。@NicolasDudebout抱歉,已删除的选项名称-应为qwerty。示例缓冲区是上面的文本。出于某种原因,使用正则表达式的示例有效,但第一个示例无效。第一个示例给出错误:错ype参数:integer-or-marker-p,nil。有什么想法吗?还有一个问题。正则表达式在没有这两个\\对的情况下工作\\的目的是什么\\您将在中找到大量有关emacs正则表达式语法的文档,例如。
    \(…\)
    在正则表达式中包含一个组,这意味着以后可以使用
    (匹配字符串1)
    检索此构造中匹配的子字符串。由于此处的正则表达式是一个elisp字符串,因此需要转义反斜杠,这将导致
    “\\(…\\)”
    construct。我不明白为什么第一个示例不起作用。您可以使用
    M-x toggle debug on error
    跟踪错误的确切位置:此后,每次抛出错误时,调试器都会被激活,向您显示哪个函数没有获得预期参数。出于某种原因,使用regex的示例可以工作,但第一个是e示例没有。第一个示例给出错误:错误的类型参数:integer-or-marker-p,nil。有什么想法吗?再问一个问题。正则表达式在没有两个\\对的情况下工作。您将找到大量有关emacs正则表达式语法的文档,\\在正则表达式中包含一个组,这意味着以后可以使用
    (匹配字符串1)
    检索此构造中匹配的子字符串。由于此处的正则表达式是一个elisp字符串,因此需要转义反斜杠,这将导致
    “\\(…\\)”
    construct。我不明白为什么第一个示例不起作用。您可以使用
    M-x toggle-d跟踪错误的确切位置