Czy mogę zastąpić wiele elementów w jednym wyrażeniu regularnym w Vimie lub perlu?

Powiedzmy, że mam ciąg "szybki brązowy lis przeskakuje nad leniwym psem "czy Mogę zmienić to na" powolny brązowy lis przeskakuje nad energicznym psem " z jednym wyrażeniem regularnym? Obecnie używam w tej sytuacji dwóch zestawów wyrażeń regularnych. (W tym przypadku używam s/quick/slow/, a następnie s/lazy/energetic/.)

7 answers

Druga część podstawienia jest podwójnym cytowanym ciągiem, więc może wystąpić każda normalna interpolacja. Oznacza to, że możesz użyć wartości przechwytywania do indeksowania w hash:

#!/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";
 32
Author: Chas. Owens,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-19 19:08:15

Możesz to zrobić w Vimie używając słownika:

:%s/quick\|lazy/\={'quick':'slow','lazy':'energetic'}[submatch(0)]/g

Spowoduje to zmianę następującego tekstu:

The quick brown fox Run quick ly next to the lazy brook.

Do:

Powoli brown fox biegłpowoli ly obok energiczny potok.

Aby zobaczyć jak to działa, zobacz :help sub-replace-expression i :help Dictionary. W skrócie,

  • \= pozwala zastąpić w wynik wyrażenia vim.
  • {'quick':'slow', 'lazy':'energetic'} jest słownikiem vim (jak hash w Perlu lub ruby lub obiekt w javascript), który używa [] do wyszukiwania.
  • submatch(0) jest dopasowanym ciągiem

Może się to przydać podczas refaktoryzacji kodu-powiedzmy, że chcesz wymienić nazwy zmiennych na foo, bar, and baz changing

  • foobar
  • barbaz
  • bazfoo

Używając sekwencji %s/// polecenia byłyby trudne, chyba że użyjesz tymczasowych nazw zmiennych - ale musisz się upewnić, że nie uderzają w nic innego. Zamiast tego możesz użyć słownika, aby zrobić to w jednym przejściu: {]}

:%s/\<\%(foo\|bar\|baz\)\>/\={'foo':'bar','bar':'baz','baz':'foo'}[submatch(0)]/g

Który zmienia ten kod

int foo = 0;
float bar = pow(2.0, (float) foo);
char baz[256] = {};

sprintf(baz,"2^%d = %f\n", foo, bar);

Do:

int bar = 0;
float baz = pow(2.0, (float) bar);
char foo[256] = {};

sprintf(foo,"2^%d = %f\n", bar, baz);

Jeśli często to robisz, możesz dodać do swojego ~/.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>)

Pozwala to na użycie polecenia :Refactor {'frog':'duck', 'duck':'frog'} i jest nieco mniej powtarzalne niż tworzenie regex dla dict ręcznie.

 49
Author: rampion,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-27 09:22:06

Możesz konkatenować podstawienia Vima:

Szybki Lis brunatny biegł szybko obok leniwego potoku.

:s/quick/slow/|s/lazy/energetic/
Powolny Lis brunatny biegł szybko obok energicznego potoku.

Zaletą jest to, że musisz wpisać swoje podstawienia tylko raz

Rgds

 14
Author: joe_zeroh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-03 15:43:58

Możesz wykonać następujące czynności.

:%s/quick\(.*\)lazy/slow\1energetic

Sztuką jest użycie parentów, aby dopasować tekst między tymi dwoma słowami. Następnie możesz odwołać się do tego tekstu w ciągu zastępczym za pomocą \1. Możesz również użyć \2 dla drugiego dopasowanego wyrażenia paren i tak dalej. Pozwala to na zastąpienie wielu słów bez zakłócania tekstu inbetween.

 8
Author: JaredPar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-19 19:06:45

W Perlu:

s/quick(.*)lazy/slow${1}energetic/;

W vim:

s/quick\(.*\)lazy/slow\1energetic/;
 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-19 19:31:00

ODPOWIEDŹ Chasa jest dobra, jedyną inną rzeczą, o której bym wspomniał, jest to, że jeśli robisz zamianę słów, prawdopodobnie chcesz być dopasowany na

\B (foo|bar|baz|qux)\B

Aby uniknąć pasujących podciągów. Jeśli wykonujesz lot zamiany słów, możesz zacząć odnajdywać wyrażenia regularne nieco ograniczające i chcieć zrobić coś w stylu:

join '', map { exists $subst{$_} ? $subst{$_} : $_ } split /\b/, $string
 0
Author: NickZoic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-19 22:57:22

Jest świetny sposób, aby to zrobić w Ruby używając gsub z blokiem:

s = "The quick brown fox jumps over the lazy dog"
subs = {'quick' => 'slow', 'lazy' => 'industrious'}
s.gsub(/quick|lazy/) { |match| subs[match] }
# => "The slow brown fox jumps over the industrious dog"
 -2
Author: allyourcode,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-19 19:36:33