如何在代码中同时交换或替换多个字符串?

时间:2010-04-06 20:59:25

标签: c bash emacs refactoring vi

给出以下代码示例:

uint8_t i, in, ni;
i = in = 2; ni = 1;
while (2 == i > ni) in++;

如何使用emacs,vi,* nix命令或其他任何内容分别用i, in, and niin, ni, and i替换inni, inin, and nini

5 个答案:

答案 0 :(得分:12)

更短的Emacs解决方案:

C-M - %(query-replace-regexp)

匹配: \< \(i \ | in \ | ni \)\> (我假设您只想匹配整个单词)

替换为: \,(case(intern \ 1)(i“in”)(in“ni”)(ni“i”))

在执行此操作之前,您需要require 'cl才能从CL包中获取case宏。没有那个包你可以达到同样的效果,但它不会那么简洁。

编辑添加:实际上,它可能像我最近在Reddit上回答类似问题时意识到的那样简洁。

匹配:\<\(?:\(i\)\|\(in\)\|ni\)\>

替换为:\,(if \1 "in" (if \2 "ni" "i"))

答案 1 :(得分:10)

如果我没有弄错的话,到目前为止提供的解决方案(使用Perl和Vim)如果要替换后面的任何替换词,则无法正常工作。特别是,没有一个解决方案适用于第一个例子:“i”将被替换为“in”,然后将被错误地替换为“ni”,然后通过后续规则返回“i”,而它应该保留作为“在”。

替换不能独立承担并连续应用;它们应该并行应用。

在Emacs中,你可以这样做:

M-x parallel-replace

并在提示符下输入

我在ni ni i

在光标和缓冲区末尾之间进行替换,如果选择了一个,则在区域中进行替换。

(如果您在~/.emacs.d/init.el中有此定义: - )

(require 'cl)
(defun parallel-replace (plist &optional start end)
  (interactive
   `(,(loop with input = (read-from-minibuffer "Replace: ")
            with limit = (length input)
            for (item . index) = (read-from-string input 0)
                            then (read-from-string input index)
            collect (prin1-to-string item t) until (<= limit index))
     ,@(if (use-region-p) `(,(region-beginning) ,(region-end)))))
  (let* ((alist (loop for (key val . tail) on plist by #'cddr
                      collect (cons key val)))
         (matcher (regexp-opt (mapcar #'car alist) 'words)))
    (save-excursion
      (goto-char (or start (point)))
      (while (re-search-forward matcher (or end (point-max)) t)
        (replace-match (cdr (assoc-string (match-string 0) alist)))))))

编辑(2013年8月20日):

一些改进:

  1. 对于只给出两个项目的特殊情况,请执行交换(即相互替换);
  2. 以与query-replace相同的方式要求确认每次更换。
  3. (require 'cl)
    (defun parallel-query-replace (plist &optional delimited start end)
      "Replace every occurrence of the (2n)th token of PLIST in
    buffer with the (2n+1)th token; if only two tokens are provided,
    replace them with each other (ie, swap them).
    
    If optional second argument DELIMITED is nil, match words
    according to syntax-table; otherwise match symbols.
    
    When called interactively, PLIST is input as space separated
    tokens, and DELIMITED as prefix arg."
      (interactive
       `(,(loop with input = (read-from-minibuffer "Replace: ")
                with limit = (length input)
                for  j = 0 then i
                for (item . i) = (read-from-string input j)
                collect (prin1-to-string item t) until (<= limit i))
         ,current-prefix-arg
         ,@(if (use-region-p) `(,(region-beginning) ,(region-end)))))
      (let* ((alist (cond ((= (length plist) 2) (list plist (reverse plist)))
                          ((loop for (key val . tail) on plist by #'cddr
                                 collect (list (prin1-to-string key t) val)))))
             (matcher (regexp-opt (mapcar #'car alist)
                                  (if delimited 'words 'symbols)))
             (to-spec `(replace-eval-replacement replace-quote
                        (cadr (assoc-string (match-string 0) ',alist
                                            case-fold-search)))))
        (query-replace-regexp matcher to-spec nil start end)))
    

答案 2 :(得分:4)

> cat foo
uint8_t i, in, ni;
i = in = 2; ni = 1;
while (2 == i > ni) in++;
> perl -p -i -e 's/\bi\b/inni/; s/\bin\b/inin/; s/\bni\b/i/;' foo
> cat foo
uint8_t inni, inin, i;
inni = inin = 2; i = 1;
while (2 == inni > i) inin++;
>

除了perl之外,欢迎使用支持正则表达式的任何其他工具。

答案 3 :(得分:2)

vim中,您可以使用|分隔多个命令,因此您可以使用%s命令进行替换:

:%s/\<i\>/inni/ | %s/\<in\>/inin/ | %s/\<ni\>/nini/

这意味着什么:

%s/search/replacement/

搜索给定的search模式,并将其替换为replacement;

符号“\<”和“\>”在此处作为字边界。

答案 4 :(得分:1)

最简单的方法是使用gedit的替换功能。

vi

%s/old/new/g将在文件中用“new”替换所有出现的“old”。