How can I swap or replace multiple strings in code at the same time?

前端 未结 5 1251
北恋
北恋 2021-01-12 10:32

Given the following code sample:

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

How can I replace i, in, and ni<

相关标签:
5条回答
  • 2021-01-12 11:03
    > 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++;
    >
    

    You're welcome to use any other tool supporting regular expressions aside from perl.

    0 讨论(0)
  • 2021-01-12 11:06

    Shorter Emacs solution:

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

    To match: \<\(i\|in\|ni\)\> (I assume you want to match whole words only)

    Replace with: \,(case (intern \1) (i "in") (in "ni") (ni "i"))

    You'll need to require 'cl at some point before doing this to get the case macro from the CL package. You could achieve the same effect without that package, but it wouldn't be as terse.

    EDITING TO ADD: Actually, it could be as terse, as I realized when answering a similar question on Reddit recently.

    To match: \<\(?:\(i\)\|\(in\)\|ni\)\>

    Replace with: \,(if \1 "in" (if \2 "ni" "i"))

    0 讨论(0)
  • 2021-01-12 11:07

    If I'm not mistaken, the solutions provided so far (using Perl and Vim) do not work correctly when any of the replacements is among the latter words to be replaced. In particular, none of the solutions works for the first example: "i" would be replaced with "in", which would then be incorrectly replaced with "ni" and then back to "i" by the subsequent rules, while it should stay as "in".

    The substitutions cannot be assumed independent and applied in succession; they should be applied in parallel.

    In Emacs, you can do this:

    M-xparallel-replace,

    and at the prompt, enter

    i in in ni ni i.

    The replacements will happen between the cursor and the end of buffer, or in a region if one is selected.

    (Provided you have this definition in your ~/.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)))))))
    

    Edit(2013-08-20):

    A few enhancements:

    1. For the special case that only two items are given, perform a swap instead (ie, replace with each other);
    2. Ask for confirmation for each replacement in the same manner as 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)))
    
    0 讨论(0)
  • 2021-01-12 11:13

    Most easiest way would be to use the replace functionality of gedit.

    In vi,

    %s/old/new/g will replace all occurrences of "old" with "new" through out the file.

    0 讨论(0)
  • 2021-01-12 11:17

    In vim you can have multiple commands, separated by |, so you could do your replacement with %s command:

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

    Shortly what it means:

    %s/search/replacement/
    

    searches for given search pattern and replaces it with replacement;

    symbols "\<" and "\>" are standing here as word boundaries.

    0 讨论(0)
提交回复
热议问题