Executando um 'perl command' a partir do shell e executando o mesmo comando do script perl usando o comando do sistema

3

Não consigo cuidar de caracteres especiais.

Eu tenho o seguinte script perl.

while(@mapping_array[$i])
{  
  chomp(@mapping_array[$i]);
  my @core= split ( /  / , $mapping_array[$i]) ;
  @core[0] =~ tr/ //ds ;   ## Deleting blank spaces
  @core[1] =~ tr/ //ds ;     
  system("perl -pi -e 's/@core[0]/@core[1]/' $testproc ");  
  print "@core[0] \n";
  print "@core[1] \n";
  $i++;
}

O problema é que minha variável @core[0] pode ser uma string simples como abc ou uma mais complexa como TEST[1] . Meu script funciona como esperado para abc , substituindo-o pelo valor de @core[1] , mas falha se meu @core[0] for TEST[1] .

Usar ? em vez de / no operador de substituição não ajuda. Como posso fazer isso corretamente?

    
por Ramneek Singh Kakkar 21.10.2015 / 11:51

4 respostas

6

Parece que você está procurando por quotemeta . Conforme explicado em perldoc -f quotemeta :

quotemeta EXPR
        Returns the value of EXPR with all the ASCII non-"word" characters
        backslashed. (That is, all ASCII characters not matching
        "/[A-Za-z_0-9]/" will be preceded by a backslash in the returned
        string, regardless of any locale settings.) This is the internal
        function implementing the "\Q" escape in double-quoted strings.

Assim, seu script seria (note que os elementos da matriz devem ser especificados como $foo[N] , não @foo[N] ):

chomp(@mapping_array);
while($mapping_array[$i])
{  
    my @core= split ( /  / , $mapping_array[$i]) ;
    $core[0] =~ tr/ //ds ;   ## // Deleting blank spaces
    $core[1] =~ tr/ //ds ;   # / fix SO highlighting
    my($k,$l)=(quotemeta($core[0]),quotemeta($core[1]))
    system("perl -pi -e 's/$k/$l/' $testproc "); 
    print "$core[0] \n$core[1] \n";
    $i++;
}
    
por 21.10.2015 / 12:13
5

A execução do Perl do Perl geralmente pode ser evitada.

for my $both (@mapping) {
    my ($regex, $replace) = split /  /, $both;
    tr/ //ds for $regex, $replace;                                                                   # // Fix SO highlighting bug.

    open my $IN,  '<', $testproc or die $!;
    open my $OUT, '>', "$testproc.new" or die $!;
    while (<$IN>) {
        s/\Q$regex/$replace/;
        print {$OUT} $_;
    }
    close $OUT or die $!;
    rename $testproc, "$testproc.old" or die $!;
    rename "$testproc.new", $testproc or die $!;
}

O \ Q corresponde a quotemeta que impede a interpretação de caracteres especiais na variável $ regex.

    
por 21.10.2015 / 12:16
4

Primeiro, desative a opção strict e warnings no topo do seu programa:

use strict;
use warnings;

Isso ajudará você a identificar erros, como @core[0] não está correto.

No entanto, o segundo problema é - você está enviando meta-caracteres para sua regex - [] significa algo especial na regex.

Então, o que você realmente precisa é da função quotemeta .

print quotemeta '@core[0]';

Que o transforma em:

\@core\[0\]

Ou

print quotemeta $core[0]; 

O que no exemplo que você dá será impresso:

TEST\[1\]

Claro, você provavelmente não precisa system() chamar perl de perl . Isso é apenas ineficiente e confuso.

    
por 21.10.2015 / 12:10
2

Use \Q no regexp para remover significado especial dos caracteres:

system("perl -pi -e 's/\Q$core[0]/$core[1]/' $testproc ");
    
por 21.10.2015 / 12:10