Regex Emacs正则表达式:替换latex表达式中的字符串

Regex Emacs正则表达式:替换latex表达式中的字符串,regex,emacs,latex,Regex,Emacs,Latex,我想用字母“n”替换任何乳胶方程式中出现的字母“n”。可以假设文档中的乳胶方程的形式为$$ 也将接受在ubuntu或Windows上可用的perl或任何其他语言/工具/应用程序的解决方案。在emacs中,我们可以利用auctex的hilighting替换所有数学环境中的字符串。(我知道这与问题不符。但是,也许这更有用。)运行下面的代码后,按M-x latex replace in math,输入源正则表达式,如\,然后输入替换字符串,如N。如果在变量名之间保留空格,则\比仅n更好,否则\sin将

我想用字母“n”替换任何乳胶方程式中出现的字母“n”。可以假设文档中的乳胶方程的形式为$$


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

在emacs中,我们可以利用auctex的hilighting替换所有数学环境中的字符串。(我知道这与问题不符。但是,也许这更有用。)运行下面的代码后,按
M-x latex replace in math
,输入源正则表达式,如
\
,然后输入替换字符串,如
N
。如果在变量名之间保留空格,则
\
比仅
n
更好,否则
\sin
将被
\sin
替换,这可能不是您想要的。但是,下面的代码也没有太大问题,因为它查询替换,您可以按'n'跳过不需要的替换

请注意,如果要替换区分大小写的选项,应禁用选项→ 忽略搜索的大小写

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

我的新首选解决方案是:

(数学中的fset'替换
`(lambda(regexp到字符串&可选的分隔起始-结束向后&rest\u忽略)
“类似于'query replace regexp',但仅在LaTeX数学环境中替换。”
,(交互式表单“查询替换regexp”)
(let((替换搜索函数)(lambda(regexp-bound-noerror)
(捕获:找到
(while(let((ret(research forward regexp-bound noerror)))
(当(保存匹配数据(texmathp))(抛出:找到ret))
(()())
(查询替换regexp regexp为字符串分隔的开始-结束向后)))

前一个更复杂的版本是:

(数学中的defun乳胶(pos)
“检查pos是否在数学环境中。”
(let((面(plist-get(位置处的文本属性)'face)))
(或(eq脸的字体)
(和(列表面)
(memq'font-latex数学脸(())))
(取消下一次数学更改(&可选绑定停留)
“从点开始搜索数学环境的下一个开始。
若停留时间为零且返回点为零,则将点放置在该位置。
否则,将点留在原来的位置,并返回零。”
(让((b点))
(inMathB(数学中的乳胶(点)))
(英马)
(捕获:找到
(while(setq b(下一个单一属性更改b'面为零界))
(setq inMath(数学b中的乳胶))
(当(或(和inMathB(空inMath))
(和(无效inMath)inMath)
(除非停留(转到char b))
(投掷:找到b(()()())))
(数学中的defun latex replace(src tgt&可选边界)
“在所有数学环境中,用TGT替换SRC。”
(交互式(列表(读取regexp“源正则表达式:”)
(读取字符串“目标字符串:”))
(省去远足
(字体锁定fontify区域(点)(最大点)))
(抓住“退出”
(让(b e repl)
(何时(数学中的乳胶(点))
(错误“最小点不应在数学环境中”))
(while(setq b(latex下一个数学更改边界))
(转到字符b)
(while(向前搜索regexp src(latex下一个数学更改边界t)'noErr)
(除非(等式替换全部)
(let((ol(生成覆盖(匹配开始0)(匹配结束0)))
(覆盖放置“面”查询替换)
(while)空
(eval(cdr(assq)(读字符“y:replace,n:don,q:quit,!:replace all”(?y?n?q?!))
"(y(setq repl t)
(?n.(setq回复号))
(?q.(setq repl'退出))
(?!(setq回复“全部()()())())))
(删除重叠部分)
(何时(eq repl'quit)
(抛出“退出零”))
(除非(等式回复号)
(替换匹配tgt(()()())))

在遇到我对Tobias答案的评论中描述的问题后,我通过向my
.emacs
中添加两个函数
query replace tex math regexp
perform replace tex math
解决了这个问题,它们的工作方式如下:

(defun query-replace-tex-math-regexp (regexp to-string &optional delimited start end backward)
  "Replace some things after point matching REGEXP with TO-STRING, but only in AucTeX math mode.
As each match is found, the user must type a character saying
what to do with it.  For directions, type \\[help-command] at that time.

In Transient Mark mode, if the mark is active, operate on the contents
of the region.  Otherwise, operate from point to the end of the buffer.

Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search regexp to the minibuffer
that reads REGEXP, or invoke replacements from
incremental search with a key sequence like `C-M-s C-M-s C-M-%'
to use its current search regexp as the regexp to replace.

Matching is independent of case if `case-fold-search' is non-nil and
REGEXP has no uppercase letters.  Replacement transfers the case
pattern of the old text to the new text, if `case-replace' and
`case-fold-search' are non-nil and REGEXP has no uppercase letters.
\(Transferring the case pattern means that if the old text matched is
all caps, or capitalized, then its replacement is upcased or
capitalized.)

Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
ignore hidden matches if `search-invisible' is nil, and ignore more
matches using `isearch-filter-predicate'.

If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
to be replaced will match a sequence of whitespace chars defined by the
regexp in `search-whitespace-regexp'.

Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
only matches surrounded by word boundaries.  A negative prefix arg means
replace backward.

Fourth and fifth arg START and END specify the region to operate on.

In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
and `\\=\\N' (where N is a digit) stands for
whatever what matched the Nth `\\(...\\)' in REGEXP.
`\\?' lets you edit the replacement text in the minibuffer
at the given position for each replacement.

In interactive calls, the replacement text can contain `\\,'
followed by a Lisp expression.  Each
replacement evaluates that expression to compute the replacement
string.  Inside of that expression, `\\&' is a string denoting the
whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
for the whole or a partial match converted to a number with
`string-to-number', and `\\#' itself for the number of replacements
done so far (starting with zero).

If the replacement expression is a symbol, write a space after it
to terminate it.  One space there, if any, will be discarded.

When using those Lisp features interactively in the replacement
text, TO-STRING is actually made a list instead of a string.
Use \\[repeat-complex-command] after this command for details."
  (interactive
   (let ((common
      (query-replace-read-args
       (concat "Query replace"
           (if current-prefix-arg
               (if (eq current-prefix-arg '-) " backward" " word")
             "")
           " regexp"
           (if (and transient-mark-mode mark-active) " in region" ""))
       t)))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
       ;; These are done separately here
       ;; so that command-history will record these expressions
       ;; rather than the values they had this time.
       (if (and transient-mark-mode mark-active)
           (region-beginning))
       (if (and transient-mark-mode mark-active)
           (region-end))
       (nth 3 common))))
  (perform-replace-tex-math regexp to-string t t delimited nil nil start end backward))





(defun perform-replace-tex-math (from-string replacements
                query-flag regexp-flag delimited-flag
            &optional repeat-count map start end backward)
  "Subroutine of `query-replace'.  Its complexity handles interactive queries.
Don't use this in your own program unless you want to query and set the mark
just as `query-replace' does.  Instead, write a simple loop like this:

  (while (re-search-forward \"foo[ \\t]+bar\" nil t)
    (replace-match \"foobar\" nil nil))

which will run faster and probably do exactly what you want.  Please
see the documentation of `replace-match' to find out how to simulate
`case-replace'.

This function returns nil if and only if there were no matches to
make, or the user didn't cancel the call."
  (or map (setq map query-replace-map))
  (and query-flag minibuffer-auto-raise
       (raise-frame (window-frame (minibuffer-window))))
  (let* ((case-fold-search
      (if (and case-fold-search search-upper-case)
          (isearch-no-upper-case-p from-string regexp-flag)
        case-fold-search))
         (nocasify (not (and case-replace case-fold-search)))
         (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
         (search-string from-string)
         (real-match-data nil)       ; The match data for the current match.
         (next-replacement nil)
         ;; This is non-nil if we know there is nothing for the user
         ;; to edit in the replacement.
         (noedit nil)
         (keep-going t)
         (stack nil)
         (replace-count 0)
         (skip-read-only-count 0)
         (skip-filtered-count 0)
         (skip-invisible-count 0)
         (nonempty-match nil)
     (multi-buffer nil)
     (recenter-last-op nil) ; Start cycling order with initial position.

         ;; If non-nil, it is marker saying where in the buffer to stop.
         (limit nil)

         ;; Data for the next match.  If a cons, it has the same format as
         ;; (match-data); otherwise it is t if a match is possible at point.
         (match-again t)

         (message
          (if query-flag
              (apply 'propertize
                     (substitute-command-keys
                      "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ")
                     minibuffer-prompt-properties))))

    ;; If region is active, in Transient Mark mode, operate on region.
    (if backward
    (when end
      (setq limit (copy-marker (min start end)))
      (goto-char (max start end))
      (deactivate-mark))
      (when start
    (setq limit (copy-marker (max start end)))
    (goto-char (min start end))
    (deactivate-mark)))

    ;; If last typed key in previous call of multi-buffer perform-replace
    ;; was `automatic-all', don't ask more questions in next files
    (when (eq (lookup-key map (vector last-input-event)) 'automatic-all)
      (setq query-flag nil multi-buffer t))

    ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
    ;; containing a function and its first argument.  The function is
    ;; called to generate each replacement like this:
    ;;   (funcall (car replacements) (cdr replacements) replace-count)
    ;; It must return a string.
    (cond
     ((stringp replacements)
      (setq next-replacement replacements
            replacements     nil))
     ((stringp (car replacements)) ; If it isn't a string, it must be a cons
      (or repeat-count (setq repeat-count 1))
      (setq replacements (cons 'replace-loop-through-replacements
                               (vector repeat-count repeat-count
                                       replacements replacements)))))

    (when query-replace-lazy-highlight
      (setq isearch-lazy-highlight-last-string nil))

    (push-mark)
    (undo-boundary)
    (unwind-protect
    ;; Loop finding occurrences that perhaps should be replaced.
    (while (and keep-going
            (if backward
            (not (or (bobp) (and limit (<= (point) limit))))
              (not (or (eobp) (and limit (>= (point) limit)))))
            ;; Use the next match if it is already known;
            ;; otherwise, search for a match after moving forward
            ;; one char if progress is required.
            (setq real-match-data
              (cond ((consp match-again)
                 (goto-char (if backward
                        (nth 0 match-again)
                          (nth 1 match-again)))
                 (replace-match-data
                  t real-match-data match-again))
                ;; MATCH-AGAIN non-nil means accept an
                ;; adjacent match.
                (match-again
                 (and
                  (replace-search search-string limit
                          regexp-flag delimited-flag
                          case-fold-search backward)
                  ;; For speed, use only integers and
                  ;; reuse the list used last time.
                  (replace-match-data t real-match-data)))
                ((and (if backward
                      (> (1- (point)) (point-min))
                    (< (1+ (point)) (point-max)))
                      (or (null limit)
                      (if backward
                          (> (1- (point)) limit)
                        (< (1+ (point)) limit))))
                 ;; If not accepting adjacent matches,
                 ;; move one char to the right before
                 ;; searching again.  Undo the motion
                 ;; if the search fails.
                 (let ((opoint (point)))
                   (forward-char (if backward -1 1))
                   (if (replace-search search-string limit
                               regexp-flag delimited-flag
                               case-fold-search backward)
                       (replace-match-data
                    t real-match-data)
                     (goto-char opoint)
                     nil))))))

      ;; Record whether the match is nonempty, to avoid an infinite loop
      ;; repeatedly matching the same empty string.
      (setq nonempty-match
        (/= (nth 0 real-match-data) (nth 1 real-match-data)))

      ;; If the match is empty, record that the next one can't be
      ;; adjacent.

      ;; Otherwise, if matching a regular expression, do the next
      ;; match now, since the replacement for this match may
      ;; affect whether the next match is adjacent to this one.
      ;; If that match is empty, don't use it.
      (setq match-again
        (and nonempty-match
             (or (not regexp-flag)
             (and (if backward
                  (looking-back search-string)
                (looking-at search-string))
                  (let ((match (match-data)))
                (and (/= (nth 0 match) (nth 1 match))
                     match))))))

      (cond
       ;; Optionally ignore matches that have a read-only property.
       ((not (or (not query-replace-skip-read-only)
             (not (text-property-not-all
               (nth 0 real-match-data) (nth 1 real-match-data)
               'read-only nil))))
        (setq skip-read-only-count (1+ skip-read-only-count)))
       ;; Optionally filter out matches.
       ((not (funcall isearch-filter-predicate
                          (nth 0 real-match-data) (nth 1 real-match-data)))
        (setq skip-filtered-count (1+ skip-filtered-count)))
       ;; filter out matches not in math mode.
       ((not (texmathp))
        (setq skip-filtered-count (1+ skip-filtered-count)))
       ;; Optionally ignore invisible matches.
       ((not (or (eq search-invisible t)
             ;; Don't open overlays for automatic replacements.
             (and (not query-flag) search-invisible)
             ;; Open hidden overlays for interactive replacements.
             (not (isearch-range-invisible
               (nth 0 real-match-data) (nth 1 real-match-data)))))
        (setq skip-invisible-count (1+ skip-invisible-count)))
       (t
        ;; Calculate the replacement string, if necessary.
        (when replacements
          (set-match-data real-match-data)
          (setq next-replacement
            (funcall (car replacements) (cdr replacements)
                 replace-count)))
        (if (not query-flag)
        (progn
          (unless (or literal noedit)
            (replace-highlight
             (nth 0 real-match-data) (nth 1 real-match-data)
             start end search-string
             regexp-flag delimited-flag case-fold-search backward))
          (setq noedit
            (replace-match-maybe-edit
             next-replacement nocasify literal
             noedit real-match-data backward)
            replace-count (1+ replace-count)))
          (undo-boundary)
          (let (done replaced key def)
        ;; Loop reading commands until one of them sets done,
        ;; which means it has finished handling this
        ;; occurrence.  Any command that sets `done' should
        ;; leave behind proper match data for the stack.
        ;; Commands not setting `done' need to adjust
        ;; `real-match-data'.
        (while (not done)
          (set-match-data real-match-data)
          (replace-highlight
           (match-beginning 0) (match-end 0)
           start end search-string
           regexp-flag delimited-flag case-fold-search backward)
          ;; Bind message-log-max so we don't fill up the message log
          ;; with a bunch of identical messages.
          (let ((message-log-max nil)
            (replacement-presentation
             (if query-replace-show-replacement
                 (save-match-data
                   (set-match-data real-match-data)
                   (match-substitute-replacement next-replacement
                                 nocasify literal))
               next-replacement)))
            (message message
                             (query-replace-descr from-string)
                             (query-replace-descr replacement-presentation)))
          (setq key (read-event))
          ;; Necessary in case something happens during read-event
          ;; that clobbers the match data.
          (set-match-data real-match-data)
          (setq key (vector key))
          (setq def (lookup-key map key))
          ;; Restore the match data while we process the command.
          (cond ((eq def 'help)
             (with-output-to-temp-buffer "*Help*"
               (princ
                (concat "Query replacing "
                    (if delimited-flag
                    (or (and (symbolp delimited-flag)
                         (get delimited-flag 'isearch-message-prefix))
                        "word ") "")
                    (if regexp-flag "regexp " "")
                    (if backward "backward " "")
                    from-string " with "
                    next-replacement ".\n\n"
                    (substitute-command-keys
                     query-replace-help)))
               (with-current-buffer standard-output
                 (help-mode))))
            ((eq def 'exit)
             (setq keep-going nil)
             (setq done t))
            ((eq def 'exit-current)
             (setq multi-buffer t keep-going nil done t))
            ((eq def 'backup)
             (if stack
                 (let ((elt (pop stack)))
                   (goto-char (nth 0 elt))
                   (setq replaced (nth 1 elt)
                     real-match-data
                     (replace-match-data
                      t real-match-data
                      (nth 2 elt))))
               (message "No previous match")
               (ding 'no-terminate)
               (sit-for 1)))
            ((eq def 'act)
             (or replaced
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)))
             (setq done t replaced t))
            ((eq def 'act-and-exit)
             (or replaced
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)))
             (setq keep-going nil)
             (setq done t replaced t))
            ((eq def 'act-and-show)
             (if (not replaced)
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)
                   real-match-data (replace-match-data
                            t real-match-data)
                   replaced t)))
            ((or (eq def 'automatic) (eq def 'automatic-all))
             (or replaced
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)))
             (setq done t query-flag nil replaced t)
             (if (eq def 'automatic-all) (setq multi-buffer t)))
            ((eq def 'skip)
             (setq done t))
            ((eq def 'recenter)
             ;; `this-command' has the value `query-replace',
             ;; so we need to bind it to `recenter-top-bottom'
             ;; to allow it to detect a sequence of `C-l'.
             (let ((this-command 'recenter-top-bottom)
                   (last-command 'recenter-top-bottom))
               (recenter-top-bottom)))
            ((eq def 'edit)
             (let ((opos (point-marker)))
               (setq real-match-data (replace-match-data
                          nil real-match-data
                          real-match-data))
               (goto-char (match-beginning 0))
               (save-excursion
                 (save-window-excursion
                   (recursive-edit)))
               (goto-char opos)
               (set-marker opos nil))
             ;; Before we make the replacement,
             ;; decide whether the search string
             ;; can match again just after this match.
             (if (and regexp-flag nonempty-match)
                 (setq match-again (and (looking-at search-string)
                            (match-data)))))
            ;; Edit replacement.
            ((eq def 'edit-replacement)
             (setq real-match-data (replace-match-data
                        nil real-match-data
                        real-match-data)
                   next-replacement
                   (read-string "Edit replacement string: "
                                            next-replacement)
                   noedit nil)
             (if replaced
                 (set-match-data real-match-data)
               (setq noedit
                 (replace-match-maybe-edit
                  next-replacement nocasify literal noedit
                  real-match-data backward)
                 replaced t))
             (setq done t))

            ((eq def 'delete-and-edit)
             (replace-match "" t t)
             (setq real-match-data (replace-match-data
                        nil real-match-data))
             (replace-dehighlight)
             (save-excursion (recursive-edit))
             (setq replaced t))
            ;; Note: we do not need to treat `exit-prefix'
            ;; specially here, since we reread
            ;; any unrecognized character.
            (t
             (setq this-command 'mode-exited)
             (setq keep-going nil)
             (setq unread-command-events
                   (append (listify-key-sequence key)
                       unread-command-events))
             (setq done t)))
          (when query-replace-lazy-highlight
            ;; Force lazy rehighlighting only after replacements.
            (if (not (memq def '(skip backup)))
            (setq isearch-lazy-highlight-last-string nil)))
          (unless (eq def 'recenter)
            ;; Reset recenter cycling order to initial position.
            (setq recenter-last-op nil)))
        ;; Record previous position for ^ when we move on.
        ;; Change markers to numbers in the match data
        ;; since lots of markers slow down editing.
        (push (list (point) replaced
;;;  If the replacement has already happened, all we need is the
;;;  current match start and end.  We could get this with a trivial
;;;  match like
;;;  (save-excursion (goto-char (match-beginning 0))
;;;          (search-forward (match-string 0))
;;;                  (match-data t))
;;;  if we really wanted to avoid manually constructing match data.
;;;  Adding current-buffer is necessary so that match-data calls can
;;;  return markers which are appropriate for editing.
                (if replaced
                (list
                 (match-beginning 0)
                 (match-end 0)
                 (current-buffer))
                  (match-data t)))
              stack))))))

      (replace-dehighlight))
    (or unread-command-events
    (message "Replaced %d occurrence%s%s"
         replace-count
         (if (= replace-count 1) "" "s")
         (if (> (+ skip-read-only-count
               skip-filtered-count
               skip-invisible-count) 0)
             (format " (skipped %s)"
                 (mapconcat
                  'identity
                  (delq nil (list
                     (if (> skip-read-only-count 0)
                         (format "%s read-only"
                             skip-read-only-count))
                     (if (> skip-invisible-count 0)
                         (format "%s invisible"
                             skip-invisible-count))
                     (if (> skip-filtered-count 0)
                         (format "%s filtered out"
                             skip-filtered-count))))
                  ", "))
           "")))
    (or (and keep-going stack) multi-buffer)))
函数
query replace tex math regexp
本质上只是
query replace regexp
的一个逐字复制,只是它调用了
perform replace tex math
而不是最后一行中的
perform replace
,并且
perform replace tex math
只是对
perform replace
块的一个稍微修改版本

;; filter out matches not in math mode.
((not (texmathp))
 (setq skip-filtered-count (1+ skip-filtered-count)))
在行前添加

;; Optionally ignore invisible matches.
texmathp
是在AucTeX中定义的,它测试光标是否在数学环境中,正如我从中学到的那样

(可以找到根据GNU通用公共许可证许可的原始功能的代码。)

my
.emacs
中的完整代码如下所示:

(defun query-replace-tex-math-regexp (regexp to-string &optional delimited start end backward)
  "Replace some things after point matching REGEXP with TO-STRING, but only in AucTeX math mode.
As each match is found, the user must type a character saying
what to do with it.  For directions, type \\[help-command] at that time.

In Transient Mark mode, if the mark is active, operate on the contents
of the region.  Otherwise, operate from point to the end of the buffer.

Use \\<minibuffer-local-map>\\[next-history-element] \
to pull the last incremental search regexp to the minibuffer
that reads REGEXP, or invoke replacements from
incremental search with a key sequence like `C-M-s C-M-s C-M-%'
to use its current search regexp as the regexp to replace.

Matching is independent of case if `case-fold-search' is non-nil and
REGEXP has no uppercase letters.  Replacement transfers the case
pattern of the old text to the new text, if `case-replace' and
`case-fold-search' are non-nil and REGEXP has no uppercase letters.
\(Transferring the case pattern means that if the old text matched is
all caps, or capitalized, then its replacement is upcased or
capitalized.)

Ignore read-only matches if `query-replace-skip-read-only' is non-nil,
ignore hidden matches if `search-invisible' is nil, and ignore more
matches using `isearch-filter-predicate'.

If `replace-regexp-lax-whitespace' is non-nil, a space or spaces in the regexp
to be replaced will match a sequence of whitespace chars defined by the
regexp in `search-whitespace-regexp'.

Third arg DELIMITED (prefix arg if interactive), if non-nil, means replace
only matches surrounded by word boundaries.  A negative prefix arg means
replace backward.

Fourth and fifth arg START and END specify the region to operate on.

In TO-STRING, `\\&' stands for whatever matched the whole of REGEXP,
and `\\=\\N' (where N is a digit) stands for
whatever what matched the Nth `\\(...\\)' in REGEXP.
`\\?' lets you edit the replacement text in the minibuffer
at the given position for each replacement.

In interactive calls, the replacement text can contain `\\,'
followed by a Lisp expression.  Each
replacement evaluates that expression to compute the replacement
string.  Inside of that expression, `\\&' is a string denoting the
whole match as a string, `\\N' for a partial match, `\\#&' and `\\#N'
for the whole or a partial match converted to a number with
`string-to-number', and `\\#' itself for the number of replacements
done so far (starting with zero).

If the replacement expression is a symbol, write a space after it
to terminate it.  One space there, if any, will be discarded.

When using those Lisp features interactively in the replacement
text, TO-STRING is actually made a list instead of a string.
Use \\[repeat-complex-command] after this command for details."
  (interactive
   (let ((common
      (query-replace-read-args
       (concat "Query replace"
           (if current-prefix-arg
               (if (eq current-prefix-arg '-) " backward" " word")
             "")
           " regexp"
           (if (and transient-mark-mode mark-active) " in region" ""))
       t)))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
       ;; These are done separately here
       ;; so that command-history will record these expressions
       ;; rather than the values they had this time.
       (if (and transient-mark-mode mark-active)
           (region-beginning))
       (if (and transient-mark-mode mark-active)
           (region-end))
       (nth 3 common))))
  (perform-replace-tex-math regexp to-string t t delimited nil nil start end backward))





(defun perform-replace-tex-math (from-string replacements
                query-flag regexp-flag delimited-flag
            &optional repeat-count map start end backward)
  "Subroutine of `query-replace'.  Its complexity handles interactive queries.
Don't use this in your own program unless you want to query and set the mark
just as `query-replace' does.  Instead, write a simple loop like this:

  (while (re-search-forward \"foo[ \\t]+bar\" nil t)
    (replace-match \"foobar\" nil nil))

which will run faster and probably do exactly what you want.  Please
see the documentation of `replace-match' to find out how to simulate
`case-replace'.

This function returns nil if and only if there were no matches to
make, or the user didn't cancel the call."
  (or map (setq map query-replace-map))
  (and query-flag minibuffer-auto-raise
       (raise-frame (window-frame (minibuffer-window))))
  (let* ((case-fold-search
      (if (and case-fold-search search-upper-case)
          (isearch-no-upper-case-p from-string regexp-flag)
        case-fold-search))
         (nocasify (not (and case-replace case-fold-search)))
         (literal (or (not regexp-flag) (eq regexp-flag 'literal)))
         (search-string from-string)
         (real-match-data nil)       ; The match data for the current match.
         (next-replacement nil)
         ;; This is non-nil if we know there is nothing for the user
         ;; to edit in the replacement.
         (noedit nil)
         (keep-going t)
         (stack nil)
         (replace-count 0)
         (skip-read-only-count 0)
         (skip-filtered-count 0)
         (skip-invisible-count 0)
         (nonempty-match nil)
     (multi-buffer nil)
     (recenter-last-op nil) ; Start cycling order with initial position.

         ;; If non-nil, it is marker saying where in the buffer to stop.
         (limit nil)

         ;; Data for the next match.  If a cons, it has the same format as
         ;; (match-data); otherwise it is t if a match is possible at point.
         (match-again t)

         (message
          (if query-flag
              (apply 'propertize
                     (substitute-command-keys
                      "Query replacing %s with %s: (\\<query-replace-map>\\[help] for help) ")
                     minibuffer-prompt-properties))))

    ;; If region is active, in Transient Mark mode, operate on region.
    (if backward
    (when end
      (setq limit (copy-marker (min start end)))
      (goto-char (max start end))
      (deactivate-mark))
      (when start
    (setq limit (copy-marker (max start end)))
    (goto-char (min start end))
    (deactivate-mark)))

    ;; If last typed key in previous call of multi-buffer perform-replace
    ;; was `automatic-all', don't ask more questions in next files
    (when (eq (lookup-key map (vector last-input-event)) 'automatic-all)
      (setq query-flag nil multi-buffer t))

    ;; REPLACEMENTS is either a string, a list of strings, or a cons cell
    ;; containing a function and its first argument.  The function is
    ;; called to generate each replacement like this:
    ;;   (funcall (car replacements) (cdr replacements) replace-count)
    ;; It must return a string.
    (cond
     ((stringp replacements)
      (setq next-replacement replacements
            replacements     nil))
     ((stringp (car replacements)) ; If it isn't a string, it must be a cons
      (or repeat-count (setq repeat-count 1))
      (setq replacements (cons 'replace-loop-through-replacements
                               (vector repeat-count repeat-count
                                       replacements replacements)))))

    (when query-replace-lazy-highlight
      (setq isearch-lazy-highlight-last-string nil))

    (push-mark)
    (undo-boundary)
    (unwind-protect
    ;; Loop finding occurrences that perhaps should be replaced.
    (while (and keep-going
            (if backward
            (not (or (bobp) (and limit (<= (point) limit))))
              (not (or (eobp) (and limit (>= (point) limit)))))
            ;; Use the next match if it is already known;
            ;; otherwise, search for a match after moving forward
            ;; one char if progress is required.
            (setq real-match-data
              (cond ((consp match-again)
                 (goto-char (if backward
                        (nth 0 match-again)
                          (nth 1 match-again)))
                 (replace-match-data
                  t real-match-data match-again))
                ;; MATCH-AGAIN non-nil means accept an
                ;; adjacent match.
                (match-again
                 (and
                  (replace-search search-string limit
                          regexp-flag delimited-flag
                          case-fold-search backward)
                  ;; For speed, use only integers and
                  ;; reuse the list used last time.
                  (replace-match-data t real-match-data)))
                ((and (if backward
                      (> (1- (point)) (point-min))
                    (< (1+ (point)) (point-max)))
                      (or (null limit)
                      (if backward
                          (> (1- (point)) limit)
                        (< (1+ (point)) limit))))
                 ;; If not accepting adjacent matches,
                 ;; move one char to the right before
                 ;; searching again.  Undo the motion
                 ;; if the search fails.
                 (let ((opoint (point)))
                   (forward-char (if backward -1 1))
                   (if (replace-search search-string limit
                               regexp-flag delimited-flag
                               case-fold-search backward)
                       (replace-match-data
                    t real-match-data)
                     (goto-char opoint)
                     nil))))))

      ;; Record whether the match is nonempty, to avoid an infinite loop
      ;; repeatedly matching the same empty string.
      (setq nonempty-match
        (/= (nth 0 real-match-data) (nth 1 real-match-data)))

      ;; If the match is empty, record that the next one can't be
      ;; adjacent.

      ;; Otherwise, if matching a regular expression, do the next
      ;; match now, since the replacement for this match may
      ;; affect whether the next match is adjacent to this one.
      ;; If that match is empty, don't use it.
      (setq match-again
        (and nonempty-match
             (or (not regexp-flag)
             (and (if backward
                  (looking-back search-string)
                (looking-at search-string))
                  (let ((match (match-data)))
                (and (/= (nth 0 match) (nth 1 match))
                     match))))))

      (cond
       ;; Optionally ignore matches that have a read-only property.
       ((not (or (not query-replace-skip-read-only)
             (not (text-property-not-all
               (nth 0 real-match-data) (nth 1 real-match-data)
               'read-only nil))))
        (setq skip-read-only-count (1+ skip-read-only-count)))
       ;; Optionally filter out matches.
       ((not (funcall isearch-filter-predicate
                          (nth 0 real-match-data) (nth 1 real-match-data)))
        (setq skip-filtered-count (1+ skip-filtered-count)))
       ;; filter out matches not in math mode.
       ((not (texmathp))
        (setq skip-filtered-count (1+ skip-filtered-count)))
       ;; Optionally ignore invisible matches.
       ((not (or (eq search-invisible t)
             ;; Don't open overlays for automatic replacements.
             (and (not query-flag) search-invisible)
             ;; Open hidden overlays for interactive replacements.
             (not (isearch-range-invisible
               (nth 0 real-match-data) (nth 1 real-match-data)))))
        (setq skip-invisible-count (1+ skip-invisible-count)))
       (t
        ;; Calculate the replacement string, if necessary.
        (when replacements
          (set-match-data real-match-data)
          (setq next-replacement
            (funcall (car replacements) (cdr replacements)
                 replace-count)))
        (if (not query-flag)
        (progn
          (unless (or literal noedit)
            (replace-highlight
             (nth 0 real-match-data) (nth 1 real-match-data)
             start end search-string
             regexp-flag delimited-flag case-fold-search backward))
          (setq noedit
            (replace-match-maybe-edit
             next-replacement nocasify literal
             noedit real-match-data backward)
            replace-count (1+ replace-count)))
          (undo-boundary)
          (let (done replaced key def)
        ;; Loop reading commands until one of them sets done,
        ;; which means it has finished handling this
        ;; occurrence.  Any command that sets `done' should
        ;; leave behind proper match data for the stack.
        ;; Commands not setting `done' need to adjust
        ;; `real-match-data'.
        (while (not done)
          (set-match-data real-match-data)
          (replace-highlight
           (match-beginning 0) (match-end 0)
           start end search-string
           regexp-flag delimited-flag case-fold-search backward)
          ;; Bind message-log-max so we don't fill up the message log
          ;; with a bunch of identical messages.
          (let ((message-log-max nil)
            (replacement-presentation
             (if query-replace-show-replacement
                 (save-match-data
                   (set-match-data real-match-data)
                   (match-substitute-replacement next-replacement
                                 nocasify literal))
               next-replacement)))
            (message message
                             (query-replace-descr from-string)
                             (query-replace-descr replacement-presentation)))
          (setq key (read-event))
          ;; Necessary in case something happens during read-event
          ;; that clobbers the match data.
          (set-match-data real-match-data)
          (setq key (vector key))
          (setq def (lookup-key map key))
          ;; Restore the match data while we process the command.
          (cond ((eq def 'help)
             (with-output-to-temp-buffer "*Help*"
               (princ
                (concat "Query replacing "
                    (if delimited-flag
                    (or (and (symbolp delimited-flag)
                         (get delimited-flag 'isearch-message-prefix))
                        "word ") "")
                    (if regexp-flag "regexp " "")
                    (if backward "backward " "")
                    from-string " with "
                    next-replacement ".\n\n"
                    (substitute-command-keys
                     query-replace-help)))
               (with-current-buffer standard-output
                 (help-mode))))
            ((eq def 'exit)
             (setq keep-going nil)
             (setq done t))
            ((eq def 'exit-current)
             (setq multi-buffer t keep-going nil done t))
            ((eq def 'backup)
             (if stack
                 (let ((elt (pop stack)))
                   (goto-char (nth 0 elt))
                   (setq replaced (nth 1 elt)
                     real-match-data
                     (replace-match-data
                      t real-match-data
                      (nth 2 elt))))
               (message "No previous match")
               (ding 'no-terminate)
               (sit-for 1)))
            ((eq def 'act)
             (or replaced
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)))
             (setq done t replaced t))
            ((eq def 'act-and-exit)
             (or replaced
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)))
             (setq keep-going nil)
             (setq done t replaced t))
            ((eq def 'act-and-show)
             (if (not replaced)
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)
                   real-match-data (replace-match-data
                            t real-match-data)
                   replaced t)))
            ((or (eq def 'automatic) (eq def 'automatic-all))
             (or replaced
                 (setq noedit
                   (replace-match-maybe-edit
                    next-replacement nocasify literal
                    noedit real-match-data backward)
                   replace-count (1+ replace-count)))
             (setq done t query-flag nil replaced t)
             (if (eq def 'automatic-all) (setq multi-buffer t)))
            ((eq def 'skip)
             (setq done t))
            ((eq def 'recenter)
             ;; `this-command' has the value `query-replace',
             ;; so we need to bind it to `recenter-top-bottom'
             ;; to allow it to detect a sequence of `C-l'.
             (let ((this-command 'recenter-top-bottom)
                   (last-command 'recenter-top-bottom))
               (recenter-top-bottom)))
            ((eq def 'edit)
             (let ((opos (point-marker)))
               (setq real-match-data (replace-match-data
                          nil real-match-data
                          real-match-data))
               (goto-char (match-beginning 0))
               (save-excursion
                 (save-window-excursion
                   (recursive-edit)))
               (goto-char opos)
               (set-marker opos nil))
             ;; Before we make the replacement,
             ;; decide whether the search string
             ;; can match again just after this match.
             (if (and regexp-flag nonempty-match)
                 (setq match-again (and (looking-at search-string)
                            (match-data)))))
            ;; Edit replacement.
            ((eq def 'edit-replacement)
             (setq real-match-data (replace-match-data
                        nil real-match-data
                        real-match-data)
                   next-replacement
                   (read-string "Edit replacement string: "
                                            next-replacement)
                   noedit nil)
             (if replaced
                 (set-match-data real-match-data)
               (setq noedit
                 (replace-match-maybe-edit
                  next-replacement nocasify literal noedit
                  real-match-data backward)
                 replaced t))
             (setq done t))

            ((eq def 'delete-and-edit)
             (replace-match "" t t)
             (setq real-match-data (replace-match-data
                        nil real-match-data))
             (replace-dehighlight)
             (save-excursion (recursive-edit))
             (setq replaced t))
            ;; Note: we do not need to treat `exit-prefix'
            ;; specially here, since we reread
            ;; any unrecognized character.
            (t
             (setq this-command 'mode-exited)
             (setq keep-going nil)
             (setq unread-command-events
                   (append (listify-key-sequence key)
                       unread-command-events))
             (setq done t)))
          (when query-replace-lazy-highlight
            ;; Force lazy rehighlighting only after replacements.
            (if (not (memq def '(skip backup)))
            (setq isearch-lazy-highlight-last-string nil)))
          (unless (eq def 'recenter)
            ;; Reset recenter cycling order to initial position.
            (setq recenter-last-op nil)))
        ;; Record previous position for ^ when we move on.
        ;; Change markers to numbers in the match data
        ;; since lots of markers slow down editing.
        (push (list (point) replaced
;;;  If the replacement has already happened, all we need is the
;;;  current match start and end.  We could get this with a trivial
;;;  match like
;;;  (save-excursion (goto-char (match-beginning 0))
;;;          (search-forward (match-string 0))
;;;                  (match-data t))
;;;  if we really wanted to avoid manually constructing match data.
;;;  Adding current-buffer is necessary so that match-data calls can
;;;  return markers which are appropriate for editing.
                (if replaced
                (list
                 (match-beginning 0)
                 (match-end 0)
                 (current-buffer))
                  (match-data t)))
              stack))))))

      (replace-dehighlight))
    (or unread-command-events
    (message "Replaced %d occurrence%s%s"
         replace-count
         (if (= replace-count 1) "" "s")
         (if (> (+ skip-read-only-count
               skip-filtered-count
               skip-invisible-count) 0)
             (format " (skipped %s)"
                 (mapconcat
                  'identity
                  (delq nil (list
                     (if (> skip-read-only-count 0)
                         (format "%s read-only"
                             skip-read-only-count))
                     (if (> skip-invisible-count 0)
                         (format "%s invisible"
                             skip-invisible-count))
                     (if (> skip-filtered-count 0)
                         (format "%s filtered out"
                             skip-filtered-count))))
                  ", "))
           "")))
    (or (and keep-going stack) multi-buffer)))
(defun query replace tex math regexp(regexp to string&可选的带分隔符的开始-结束向后)
将点匹配REGEXP后的某些内容替换为TO-STRING,但仅在AucTeX数学模式下。
当找到每个匹配项时,用户必须键入一个字符
如何处理。有关说明,请在此时键入\\[help command]。
在瞬态标记模式下,如果标记处于活动状态,则对内容进行操作
否则,从点到缓冲区的末尾进行操作。
使用\\\\[下一个历史元素]\
将最后一个增量搜索regexp拉入微型缓冲区
从中读取REGEXP或调用替换的
使用类似“C-M-s C-M-s C-M-%”的键序列进行增量搜索
将其当前搜索regexp用作要替换的regexp。
如果“case fold search”为非零且
REGEXP没有大写字母。替换将转移大小写
旧文本到新文本的模式,如果“case replace”,以及
`ca