Usando el editor de pantalla vi haría esto

%s/^drop table .*/exec rename_table('&')/g

Lo que me permite formatear la cadena encontrada. Necesito hacer lo mismo en Perl.

He escrito un módulo al que le paso el patrón $regexp y las cadenas de reemplazo $newtxt.

Este módulo hace

if ( $_ !~ /$regexp/ ) {
    print FOUT;
}
else {
    s/$regexp/$newtxt/g;
    print FOUT;
}

Y lo intenté

perl_swap( '(drop table .*);' , 'echo $3;' )

Esperando que el nombre de la tabla encontrada, el tercer argumento, se asigne a $3.

1
slashlos 7 mar. 2018 a las 03:19

3 respuestas

La mejor respuesta

Está buscando String :: Substitution 's gsub_modify.

use String::Substitution qw( gsub_modify );

my $pat = 'drop table (.*);';
my $repl = 'echo $1;';
local $_ = 'drop table foo;';
gsub_modify($_, $pat, $repl);
say;
1
ikegami 7 mar. 2018 a las 01:39

Lo que estás pidiendo es (en su mayoría) imposible. Perl no trata ningún carácter en la cadena de reemplazo especialmente.

Lo que puede hacer es capturar (explícita o implícitamente) el texto coincidente y usar una de las variables especiales en la parte de reemplazo ($1, $2, $&, etc.), pero eso solo funciona porque la parte de reemplazo es code . En su caso, s/$regexp/$newtxt/g, la única variable es $newtxt, y su contenido no se vuelve a explorar para una mayor expansión.

Es posible que pueda engañar al código s/$regexp/$newtxt/g pasando un objeto con una cadena de caracteres sobrecargada como $newtxt, pero sería mucho mejor (es decir, más fácil y más fácil de mantener) cambiar el código. De hecho, el código existente ya es un poco tonto:

if ($_ !~ /$regexp/)
{
    print FOUT;
}
else
{
    s/$regexp/$newtxt/g;
    print FOUT;
}

Se puede simplificar a solo

s/$regexp/$newtxt/g;
print FOUT;

Para permitir el reemplazo dinámico, la interfaz natural es usar una función, no una cadena:

s/$regexp/ $newtxt->() /eg;

Aquí /e le dice a Perl que la parte de reemplazo debe analizarse como un bloque de código, no como una cadena entre comillas. La llamada se vería así

perl_swap( 'drop table (.*);' , sub { "echo $1;" } );

$1 es el contenido del primer grupo de captura ( ).

Por otro lado, si la interfaz debe usar solo cadenas, debe hacer un poco más de trabajo manual o usar un módulo que lo haga por usted. Por ejemplo:

use Data::Munge qw(replace);
...
$_ = replace($_, $regexp, $newtxt, 'g');

Esto permite llamadas del formulario

perl_swap( 'drop table (.*);' , 'echo $1;' );

Porque Data::Munge::replace explora explícitamente y expande secuencias $ como $1 en la cadena de reemplazo.

1
melpomene 7 mar. 2018 a las 00:55

Creo que esto hará lo que quieras.

    #!/usr/bin/env perl

    # always use these two
    use strict;
    use warnings;

    # use autodie to automatically die on open errors
    use autodie;

    my $s = 'drop table FOO';
    print "$s\n";

    if( $s =~ s/^drop table (.*)/exec rename_table('&')/ ){
        my $captured = $1;
        $s =~ s/\&/$captured/;
    }

    print "$s\n";
0
shawnhcorey 8 mar. 2018 a las 10:45