Fonction de recherche / remplacement pour l'échange de texte

12

Je me retrouve fréquemment à essayer de remplacer par exemple fooavec baret baravec foodans un tampon.

La façon dont je le fais habituellement est soit:

  • 3-requête remplace: aaa -> @@@, bbb -> aaa,@@@ -> bbb
  • abandonnez l'automatisation et faites simplement le remplacement à la main

Je suppose qu'il est possible de faire fonctionner quelque chose en utilisant la ,syntaxe query-replace-regexppour tester si la chaîne correspondante est aaaou bbb. Mais la syntaxe résultante serait trop lourde, donc je ne l'ai jamais vraiment essayée.

Le fait est que, étant donné la fréquence d'une tâche, je pense qu'il doit y avoir une meilleure façon de procéder en une seule étape, soit intégrée, soit dans un package existant. Y a-t-il?

T. Verron
la source
Il peut y avoir une voie en une seule étape, mais votre première voie n'est pas mauvaise, OMI. Et si vous choisissez la bonne chaîne de remplacement, vous pouvez simplement effectuer un remplacement sans requête pour la deuxième passe.
Drew
@Drew Pour régulier query-replace, je sais que c'est généralement plus rapide M-% str1 str2que de déplacer le point et de faire le changement à la main. C'est bien, car je n'ai pas à perdre de temps à penser à ce qui sera le plus rapide, même s'il n'y a qu'une seule occurrence de str1. Idéalement, j'aimerais que l'inversion de texte soit tout aussi rapide, afin de pouvoir l'utiliser sans y penser également.
T. Verron du
Quelqu'un fournira une réponse simple. Vous pouvez sans aucun doute faire ce que vous demandez, par exemple, en utilisant une expression Lisp pour le remplacement, en référençant le texte à remplacer. Par exemple, utilisez quelque chose de similaire à l'idiome de swap (setq a (prog1 b (setq b a))). Et il peut même y avoir un moyen plus simple.
Drew
2
Je ne trouve pas \,(if \1 "b" "a")particulièrement moche (contre une expression régulière de \(a\)\|b), mais les mots doivent quand même être tapés deux fois, si cela vous dérange.
politza
2
Pourquoi pas \(aaa\)\|bbb?
politza

Réponses:

8

Voici une petite commande qui fera cela:

(defun query-swap-strings (from-string to-string &optional delimited start end)
  "Swap occurrences of FROM-STRING and TO-STRING."
  (interactive
   (let ((common
          (query-replace-read-args
           (concat "Query swap"
                   (if current-prefix-arg
                       (if (eq current-prefix-arg '-) " backward" " word")
                     "")
                   (if (use-region-p) " in region" ""))
           nil)))
     (list (nth 0 common) (nth 1 common) (nth 2 common)
           (if (use-region-p) (region-beginning))
           (if (use-region-p) (region-end)))))
  (perform-replace
   (concat "\\(" (regexp-quote from-string) "\\)\\|" (regexp-quote to-string))
   `(replace-eval-replacement replace-quote (if (match-string 1) ,to-string ,from-string))
   t t delimited nil nil start end))
link0ff
la source
Merci, c'est beaucoup plus élaboré que quelque chose que j'aurais écrit moi-même! Peut-être pourriez-vous élaborer sur les fonctionnalités implémentées? Je vois qu'avec l'argument préfixe vous revenez en arrière, qu'il n'effectue le remplacement qu'en région si besoin ... Ou est-ce juste une réécriture de query-replacepour l'inversion, afin qu'il conserve toutes ses fonctionnalités? Il ne correspond pas à 100% à la définition de mes emacs, mais je suis toujours avec 24,5 ...
T. Verron
@ T.Verron Il s'agit simplement d'un corps standard de la query-replacefamille de fonctions de la dernière version, il conserve donc toutes les fonctionnalités. À la fin de la fonction, j'ai ajouté ma méthode recommandée pour permuter les chaînes mentionnée dans le manuel Emacs.
link0ff
J'ai probablement accepté trop vite. La fonction ne fonctionne ici (emacs 24.3) que si je commente backwardet region-noncontiguous-pde l'appel à perform-replace. Est-ce un problème général ou cela signifie-t-il que l'interface perform-replacea changé entre les versions?
T. Verron
Oui, l'interface a changé avec ces 2 arguments ajoutés dans la dernière version, donc ils n'existent pas dans les précédents,
link0ff
2
Cette solution semble également convenir maintenant.
Nom du
9

Installer plur

et exécutez la commande plur-query-replace

et entrée {foo,bar}et son remplacement{bar,foo}

Appuyez sur ypour remplacer les occurrences comme vous le souhaitez.

Il existe également des variantes non interactives et de type isearch de cette commande.

InHarmsWay
la source
Merci! Le but de plur est aussi quelque chose que j'ai parfois recherché, je vais certainement y jeter un œil. Ma seule hésitation vient du commentaire de l'auteur du package ci-dessus ...;)
T. Verron
1
plurrequiert emacs 24.4.
T. Verron