如何在代码中同时交换或替换多个字符串?
给出以下代码示例:
uint8_t i, in, ni; i = in = 2; ni = 1; while (2 == i > ni) in++;
如何使用emacs,vi,* nix命令或其他任何内容分别用in, ni, and i
或inni, inin, and nini
替换i, in, and ni
?
如果我没有弄错的话,到目前为止提供的解决方案(使用Perl和Vim)如果要替换后面的任何替换词,则无法正常工作。 特别是,没有一个解决方案适用于第一个例子:“i”将被替换为“in”,然后将其错误地替换为“ni”,然后通过后续规则返回“i”,同时它应该保留作为“在”。
替换不能独立承担并连续应用; 它们应该并行应用。
在Emacs中,您可以这样做:
Mx 并行替换 ,
并在提示符下输入
我在ni ni ni 。
替换将发生在光标和缓冲区的末尾之间,或者在一个区域中(如果选择了一个)。
(如果你在~/.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)))))))
编辑(二零一三年八月二十零日):
一些增强function:
- 对于只给出两个项目的特殊情况,改为执行交换(即相互替换);
- 以与
query-replace
相同的方式query-replace
每次替换的确认。
(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)))
更短的Emacs解决方案:
CM-% (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"))
> 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之外,欢迎使用支持正则表达式的任何其他工具。
在vim
您可以使用多个命令,以|
分隔 ,所以你可以用%s
命令替换:
:%s/\/inni/ | %s/\/inin/ | %s/\/nini/
简而言之:
%s/search/replacement/
搜索给定的search
模式并将其替换为replacement
;
符号“ \<
”和“ \>
”在这里作为单词边界。
最简单的方法是使用gedit的替换function。
在vi
,
%s/old/new/g
将在文件中替换所有出现的“old”和“new”。