2012-03-15 14 views
13

Estoy intentando escapar de varios caracteres especiales en una cadena dada usando perl regex. Funciona bien para todos los personajes a excepción del signo de dólar. He intentado lo siguiente:

my %special_characters; 
$special_characters{"_"} = "\\_"; 
$special_characters{"$"} = "\\$"; 
$special_characters{"{"} = "\\{"; 
$special_characters{"}"} = "\\}"; 
$special_characters{"#"} = "\\#"; 
$special_characters{"%"} = "\\%"; 
$special_characters{"&"} = "\\&"; 

my $string = '$foobar'; 
foreach my $char (keys %special_characters) { 
    $string =~ s/$char/$special_characters{$char}/g; 
} 
print $string; 

Respuesta

17

Prueba esto:

my %special_characters; 
$special_characters{"_"} = "\\_"; 
$special_characters{"\\\$"} = "\\\$"; 
$special_characters{"{"} = "\\{"; 
$special_characters{"}"} = "\\}"; 
$special_characters{"#"} = "\\#"; 
$special_characters{"%"} = "\\%"; 
$special_characters{"&"} = "\\&"; 

ve raro, ¿verdad? Su expresión regular tiene que buscar la manera siguiente:

s/\$/\$/g 

En la primera parte de la expresión regular, "$" necesita ser escapado, porque es una expresión regular carácter especial que indica el final de la cadena.

La segunda parte de la expresión regular se considera una cadena "normal", donde "$" no tiene un significado especial. Por lo tanto, la barra diagonal inversa es una barra invertida real, mientras que en la primera parte se usa para escapar del signo de dólar.

Además, en la definición de variable necesita escapar de la barra diagonal inversa así como también del signo de dólar, porque ambos tienen un significado especial en cadenas de comillas dobles.

+2

Mejor enfoque: use 'quotemeta()' o 's/\ Q $ char \ E/...' Debería recordar hacer esto para cada $ variable, ya que las expresiones regulares las interpolan. – hhaamu

0

$ tiene un significado especial en regexp, a saber, "fin de cadena". Usted sería mejor con algo como esto:

# escape special characters, join them into a single line 
my $chars = join '', map { "\\$_" } keys %special_characters; 
$string =~ s/([$chars])/$special_characters{$1}/g; 

Además, Perl no le gusta "$" tanto, un mejor uso '$' comillas simples (=> sin interpolación).

ACTUALIZACIÓN: Lo siento, estaba escribiendo esto en un apuro => demasiadas modificaciones :(

+0

Gracias por sus comentarios, ¡su solución parece realmente elegante! Sin embargo, estoy obligado a usar el código más fácil (trabajo en equipo) ... Gracias por el encabezado de las comillas simples –

1

No es necesario un hash si usted está reemplazando cada personaje consigo mismo precedido por una barra invertida Justo. coincidir con lo que necesita y poner una barra invertida delante de él:.

s/($re)/"\\$1"/eg; 

para construir la expresión regular para todos los personajes, Regexp::Assemble es muy agradable

use v5.10.1; 
use Regexp::Assemble; 

my $ra = Regexp::Assemble->new; 

my @specials = qw(_ $ { } # % &); 

foreach my $char (@specials) { 
    $ra->add("\\Q$char\\E"); 
    } 

my $re = $ra->re; 
say "Regex is $re"; 

while(<DATA>) { 
    s/($re)/"\\$1"/eg; 
    print; 
    } 

__DATA__ 
There are $100 dollars 
Part #1234 
Outside { inside } Outside 

Observe cómo, en la primera línea de entrada, Regexp :: Assemble ha reorganizado mi patrón. No es sólo la pegadas entre sí fragmentos de las piezas que he ido añadiendo:

Regex is (?^:(?:[#$%&_]|\{|\})) 
There are \$100 dollars 
Part \#1234 
Outside \{ inside \} Outside 

Si desea agregar más personajes, que acaba de poner al personaje en @specials. Todo lo demás sucede por ti.

Cuestiones relacionadas