Emacs正则表达式:替换乳胶方程中的字符串

Eva*_*Aad 3 regex emacs latex

我想将所有在LaTeX方程式中出现的所有字母'n'替换为字母'N'。可以假定文档中的LaTeX方程的格式为$ ... $

也将接受perl或ubuntu或Windows上随时可用的任何其他语言/工具/应用程序的解决方案。

Tob*_*ias 5

在 emacs 中,我们可以利用 auctex 的突出显示来替换所有数学环境中的字符串。(我知道这偏离了问题。但是,也许这更有用。)运行下面的代码后,按M-x latex-replace-in-math并输入源正则表达式,例如\<n\>,然后输入替换字符串,例如N. 如果您在变量名之间保留空格,那么\<n\>nelse更好,也\sin将被替换\siN为可能不是您想要的。但是,这对于下面的代码来说也不是什么大问题,因为它会查询替换,您可以按“n”跳过不需要的替换。

请注意,如果您想替换区分大小写的内容,您应该停用Options ? 忽略大小写搜索

用户 cgogolin 的回答给了我一个新的想法。

我新的首选解决方案是:

(fset 'latex-replace-in-math
      `(lambda (regexp to-string &optional delimited start end backward &rest _ignore)
     "Like `query-replace-regexp' but only replaces in LaTeX-math environments."
     ,(interactive-form 'query-replace-regexp)
     (let ((replace-re-search-function (lambda (regexp bound noerror)
                         (catch :found
                           (while (let ((ret (re-search-forward regexp bound noerror)))
                            (when (save-match-data (texmathp)) (throw :found ret))
                            ret))))))
       (query-replace-regexp regexp to-string delimited start end backward))))
Run Code Online (Sandbox Code Playgroud)

前一个更复杂的版本是:

(defun latex-in-math (pos)
  "Check whether pos is in math environment."
  (let ((face (plist-get (text-properties-at pos) 'face)))
    (or (eq face 'font-latex-math-face)
    (and (listp face)
         (memq 'font-latex-math-face face)))))

(defun latex-next-math-change (&optional bound stay)
  "Starting at point search for next beginning of math environment.
Place point there if STAY is nil and return point.
Else leave point where it was and return nil."
  (let ((b (point))
    (inMathB (latex-in-math (point)))
    inMath)
    (catch :found
      (while (setq b (next-single-property-change b 'face nil bound))
    (setq inMath (latex-in-math b))
    (when (or (and inMathB (null inMath))
          (and (null inMathB) inMath))
      (unless stay (goto-char b))
      (throw :found b))))))

(defun latex-replace-in-math (src tgt &optional bound)
  "In all math-environments replace SRC with TGT."
  (interactive (list (read-regexp "Source regular expression:")
             (read-string "Target string:")))
  (save-excursion
    (font-lock-fontify-region (point) (point-max)))
  (catch 'quit
    (let (b e repl)
      (when (latex-in-math (point))
    (error "point-min should not be in math environment"))
      (while (setq b (latex-next-math-change bound))
    (goto-char b)
    (while (search-forward-regexp src (latex-next-math-change bound t) 'noErr)
      (unless (eq repl 'all)
        (let ((ol (make-overlay (match-beginning 0) (match-end 0))))
          (overlay-put ol 'face 'query-replace)
          (while (null 
              (eval (cdr (assq (read-char "y: replace, n: don't, q: quit, !: replace all" '(?y ?n ?q ?!))
                       '((?y . (setq repl t))
                     (?n . (setq repl 'no))
                     (?q . (setq repl 'quit))
                     (?! . (setq repl 'all))))))))
          (delete-overlay ol))
        (when (eq repl 'quit)
          (throw 'quit nil)))
      (unless (eq repl 'no)
        (replace-match tgt)))))))
Run Code Online (Sandbox Code Playgroud)


pav*_*vel 5

我的解决方案受到Tobias的启发,但isearch-filter-predicate用于过滤而不是修改的内部query-replace-regexp。这至少需要Emacs 24。

另外,我只使用区分大小写的搜索并替换数学,因此(case-fold-search nil)在下面的函数中进行了设置。

(defun latex-replace-in-math ()
"Call `query-replace-regexp' with `isearch-filter-predicate' set to filter out matches outside LaTeX math environments."
(interactive)
(let ((isearch-filter-predicate
 (lambda (BEG END)
   (save-excursion (save-match-data (goto-char BEG) (texmathp)))))
(case-fold-search nil))
(call-interactively 'query-replace-regexp)))
Run Code Online (Sandbox Code Playgroud)