Как я могу подкачать или заменить несколько строк в коде одновременно?

Учитывая следующий пример кода:

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

Как я могу заменить i, in, and ni, соответственно с также in, ni, and i или inni, inin, and nini использование emacs, vi, *отклоняет команды или что-либо еще?

7
задан Yktula 6 April 2010 в 20:59
поделиться

5 ответов

Если я не ошибаюсь, решения, предоставленные до сих пор (с использованием Perl и Vim), работают некорректно, если какая-либо из замен входит в число последних слов, подлежащих замене. В частности, ни одно из решений не работает для первого примера: «i» будет заменено на «in», которое затем будет неправильно заменено на «ni», а затем обратно на «i» по последующим правилам, в то время как оно должно остаться как в".

Замены не могут считаться независимыми и применяться последовательно; их следует применять параллельно.

В Emacs вы можете сделать это:

M-x parallel-replace ,

и в командной строке введите

i in in 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-08-20):

Несколько улучшений:

  1. Для особого случая, когда заданы только два элемента, вместо этого выполните обмен (т. Е. Замену друг на друга);
  2. Запрашивать подтверждение для каждой замены таким же образом, как запрос-замена .
(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)))
11
ответ дан 6 December 2019 в 05:54
поделиться

В vim вы можете иметь несколько команд, разделенных |, поэтому вы могли бы выполнить замену с помощью %s команды:

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

Коротко, что это значит:

%s/search/replacement/

ищет заданный search шаблон и заменяет его на replacement;

символы "\<" и "\>" стоят здесь как границы слов.

2
ответ дан 6 December 2019 в 05:54
поделиться

Самым простым способом будет использование функции replace в gedit.

В vi,

%s/old/new/g заменит все вхождения "old" на "new" во всем файле.

1
ответ дан 6 December 2019 в 05:54
поделиться
> 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.

4
ответ дан 6 December 2019 в 05:54
поделиться

Укороченное решение Emacs:

CM -% (запрос-замена-регулярное выражение)

Для соответствия: \ <\ (i \ | in \ | ni \) \> (Я предполагаю, что вы хотите сопоставить только слова целиком)

Замените на: \, (case (intern \ 1) (i "in") (in "ni") (ni "i"))

Вам нужно будет в какой-то момент потребовать 'cl , прежде чем делать это, чтобы получить макрос case из пакета CL. Вы могли бы добиться того же эффекта и без этого пакета, но это было бы не так кратко.

РЕДАКТИРОВАНИЕ ДЛЯ ДОБАВЛЕНИЯ: На самом деле, это могло бы быть так же кратко, как я понял, недавно отвечая на аналогичный вопрос на Reddit.

Для соответствия: \ <\ (?: \ (I \) \ | \ (in \) \ | ni \) \>

Заменить на: \, (если \ 1 " in "(if \ 2" ni "" i "))

13
ответ дан 6 December 2019 в 05:54
поделиться
Другие вопросы по тегам:

Похожие вопросы: