Perl qr // e substituição
-
11-07-2019 - |
Pergunta
Eu estou escrevendo um pequeno programa que leva a entrada do usuário usando Getops, e com base nele, o programa quer tentar corresponder a um padrão contra algum texto, ou o texto substituto para o combinado.
O problema que estou tendo é que eu não posso começar a parte substituição ao trabalho. Eu estou olhando para a qr // entrada nas páginas man: http : //perldoc.perl.org/perlop.html#Regexp-Quote-Like-Operators mas eu não estou tendo nenhuma sorte com isso. Eu tentei modelar o meu código exatamente como os docs neste caso. Eu compilar um padrão de jogo, e substituir isso em uma substituição.
Alguém poderia apontar onde eu estou indo errado? (Não se preocupe com a segurança muito, este é apenas um pequeno script para uso pessoal)
Aqui está o que eu estou olhando para:
if($options{r}){
my $pattern = $options{r};
print "\nEnter Replacement text: ";
my $rep_text = <STDIN>;
#variable grab, add flags to pattern if they exist.
$pattern .= 'g' if $options{g};
$pattern .= 'i' if $options{i};
$pattern .= 's' if $options{s};
#compile that stuff
my $compd_pattern = qr"$pattern" or die $@;
print $compd_pattern; #debugging
print "Please enter the text you wish to run the pattern on: ";
my $text = <STDIN>;
chomp $text;
#do work and display
if($text =~ s/$compd_pattern/$rep_text/){ #if the text matched or whatever
print $text;
}
else{
print "$compd_pattern on \n\t{$text} Failed. ";
}
} #end R FLAG
Quando eu executá-lo com -r "/ mate /" -i, e digite o texto de substituição 'Mateus', sobre o texto 'mate', ele falhar. Por que isso?
EDIT:
Obrigado pelas respostas caras! Isso foi realmente muito útil. Eu combinei ambas as sugestões em uma solução de trabalho para o problema. Eu tenho que lidar com a / g bandeira um pouco diferente. Aqui está o exemplo de trabalho:
if($options{r}){
my $pattern = $options{r};
print "\nEnter Replacement text: ";
my $rep_text = <STDIN>;
chomp $rep_text;
#variable grab, add flags to pattern if they exist.
my $pattern_flags .= 'i' if $options{i};
$pattern_flags .= 's' if $options{s};
print "Please enter the text you wish to run the pattern on: ";
my $text = <STDIN>;
chomp $text;
#do work and display
if($options{g}){
if($text =~ s/(?$pattern_flags:$pattern)/$rep_text/g){ #if the text matched or whatever (with the g flag)
print $text;
}
else{
print "$pattern on \n\t{$text} Failed. ";
}
}
else{
if($text =~ s/(?$pattern_flags:$pattern)/$rep_text/){ #if the text matched or whatever
print $text;
}
else{
print "$pattern on \n\t{$text} Failed. ";
}
}
} #end R FLAG
Solução
Como o caos aponta, você vai encontrar algumas dificuldades usando qr//
. Você realmente precisa de pré-compilar o padrão? Se não, uma estratégia como este trabalho poder:
my $pattern = 'matt';
my $text = 'Matt';
my $rep_text = 'Matthew';
my $pattern_opts = 'i';
print $text, "\n" if $text =~ s/(?$pattern_opts:$pattern)/$rep_text/;
Atualização em resposta ao seu novo código : você pode considerar o uso de uma abordagem como esta:
my ($orig, $patt, $rep, $flags) = qw(FooFooFoo foo bar ig);
my $make_replacement = $flags =~ s/g// ?
sub { $_[0] =~ s/(?$flags:$patt)/$rep/g } :
sub { $_[0] =~ s/(?$flags:$patt)/$rep/ }
;
if ( $make_replacement->($orig) ){
print $orig;
}
else {
print "Failed...";
}
Outras dicas
Executar com -r "matt"
, não -r "/matt/"
. Você não precisa, e de fato não pode, delimitadores padrão de alimentação na sua expressão de opção. As citações são os delimitadores na sua qr
. Por isso é realmente procurando matt
com barras em torno dele, a maneira como você está funcionando, o que não é o que você quer. Você está tentando usar as aspas para dizer Perl para tratar sua cadeia padrão como se fosse código fonte, mas, infelizmente, você não pode fazer isso.
Todos aqueles padrão acrescenta que você está fazendo para as outras opções também não trabalho. Você precisa mudar a maneira de compilar o regex se você quiser fazer tudo isso. Algo como isso pode fazê-lo por /i
e /s
:
my $compd_pattern = qr/$pattern/ or die $@;
$compd_pattern = qr/$compd_pattern/i if $options{i};
$compd_pattern = qr/$compd_pattern/s if $options{s};
Para /g
você vai precisar para suportar uma versão alternativa da busca / substituição. /g
não é um modificador válida para qr//
.