Disons que j'ai la chaîne "Le renard brun rapide saute par-dessus le chien paresseux" puis-je changer ceci en "Le renard brun lent saute par-dessus le chien énergique" avec une expression régulière? Actuellement, j'utilise deux ensembles d'expressions régulières pour cette situation. (Dans ce cas, j'utilise s/quick/slow/
suivi de s/lazy/energetic/
.)
La deuxième partie d'une substitution est une chaîne à double guillemet, de sorte que toute interpolation normale peut avoir lieu. Cela signifie que vous pouvez utiliser la valeur de la capture pour indexer dans un hachage:
#!/usr/bin/Perl
use strict;
use warnings;
my %replace = (
quick => "slow",
lazy => "energetic",
);
my $regex = join "|", keys %replace;
$regex = qr/$regex/;
my $s = "The quick brown fox jumps over the lazy dog";
$s =~ s/($regex)/$replace{$1}/g;
print "$s\n";
Vous pouvez le faire dans vim en utilisant un dictionnaire:
:%s/quick\|lazy/\={'quick':'slow','lazy':'energetic'}[submatch(0)]/g
Cela va changer le texte suivant:
Le rapide renard brun a couru rapide ly à côté du paresseux ruisseau.
dans:
Le le - lent renard brun a couru lentement tout près du energetic ruisseau.
Pour voir comment cela fonctionne, voir :help sub-replace-expression
et :help Dictionary
. En bref,
\=
vous permet de substituer le résultat d'une expression vim. {'quick':'slow', 'lazy':'energetic'}
est un dictionnaire vim (comme un hachage en Perl ou Ruby, ou un objet en javascript) qui utilise []
pour les recherches. submatch(0)
est la chaîne correspondante Cela peut s'avérer utile lors du refactoring de code - par exemple, vous voulez échanger les noms de variable pour foo
, bar
et baz
en changeant
foo
→ bar
bar
→ baz
baz
→ foo
L'utilisation d'une séquence de commandes %s///
serait délicate, à moins d'utiliser des noms de variables temporaires, mais vous devez vous assurer que celles-ci ne touchent rien d'autre. Au lieu de cela, vous pouvez utiliser un dictionnaire pour le faire en un seul passage:
:%s/\<\%(foo\|bar\|baz\)\>/\={'foo':'bar','bar':'baz','baz':'foo'}[submatch(0)]/g
Ce qui change ce code
int foo = 0;
float bar = pow(2.0, (float) foo);
char baz[256] = {};
sprintf(baz,"2^%d = %f\n", foo, bar);
dans:
int bar = 0;
float baz = pow(2.0, (float) bar);
char foo[256] = {};
sprintf(foo,"2^%d = %f\n", bar, baz);
Si vous vous trouvez souvent en train de faire cela, vous voudrez peut-être ajouter ce qui suit à votre ~/.vimrc
:
" Refactor the given lines using a dictionary
" replacing all occurences of each key in the dictionary with its value
function! Refactor(dict) range
execute a:firstline . ',' . a:lastline . 's/\C\<\%(' . join(keys(a:dict),'\|'). '\)\>/\='.string(a:dict).'[submatch(0)]/ge'
endfunction
command! -range=% -nargs=1 Refactor :<line1>,<line2>call Refactor(<args>)
Cela vous permet d'utiliser la commande :Refactor {'frog':'duck', 'duck':'frog'}
et est légèrement moins moins répétitif que la création manuelle de l'expression rationnelle pour le dict.
Vous pouvez concaténer les substitutions de vim:
Le renard brun rapide a couru rapidement à côté du ruisseau paresseux.
:s/quick/slow/|s/lazy/energetic/
Le lent renard brun a couru rapidement à côté du ruisseau énergétique.
L’avantage ici est que vous devez taper vos substitutions une seule fois.
Rgds
Vous pouvez faire ce qui suit.
:%s/quick\(.*\)lazy/slow\1energetic
L'astuce consiste à utiliser les parenthèses pour faire correspondre le texte entre les deux mots. Vous pouvez ensuite référencer ce texte dans la chaîne de substitution en utilisant \1
. Vous pouvez également utiliser \2
pour la deuxième expression paren correspondante, etc. Cela vous permet de remplacer plusieurs mots sans perturber le texte entre les deux.
En Perl:
s/quick(.*)lazy/slow${1}energetic/;
En vim:
s/quick\(.*\)lazy/slow\1energetic/;
La réponse de Chas est bonne, la seule autre chose que je voudrais mentionner est que si vous effectuez des échanges de mots, vous voulez probablement faire correspondre
\ b (foo | bar | baz | qux)\b
pour éviter de faire correspondre les sous-chaînes. Si vous faites un lot de permutation de Word, vous pourriez commencer à trouver les expressions rationnelles un peu limitantes et à vouloir faire quelque chose comme:
join '', map { exists $subst{$_} ? $subst{$_} : $_ } split /\b/, $string