2011-08-01 11 views
5

Estoy usando Perl 5.10.6 en Mac 10.6.6. Quiero ejecutar una búsqueda simple y reemplazar con un archivo de lo que he intentado:¿Cómo puedo usar 's ///' si mi cadena contiene un '/'?

my $searchAndReplaceCmd = "perl -pi -e 's/\\Q${localTestDir}\\E//g' ${testSuiteFile}"; 
system($searchAndReplaceCmd); 

pero el problema anterior es la variable $localTestDir contiene separadores de directorios ("/"), y esto arruina la expresión regular ...

Bareword encontró donde el operador espera en la línea -e 1, cerca de "s/\ Q/home/selenio"

Backslash encontró donde el operador esperado en -e línea 1, cerca de "Live \" error de sintaxis at -e línea 1 , Cerca de "s/\ Q/home/selenio"

patrón de búsqueda no termina en la línea -e 1.

¿Cómo hago una búsqueda y reemplazo en un archivo cuando la variable en cuestión contiene ¿Caracteres de expresión regular? Gracias.

Respuesta

2

pregunta es por qué usted hace una búsqueda y reemplazar dentro de Perl, a través de la cáscara, dentro de Perl. Parece una forma indirecta de hacer las cosas, y te encontrarás con problemas con la interpolación del intérprete de comandos.

El \Q ... \E debe anular los caracteres especiales en su cadena, por lo que / "debería" no ser un problema. De perlre:

\Q   quote (disable) pattern metacharacters till \E 

Aquí hay una alternativa (no probado), toda la solución del Perl. Si desea estar más seguro, cambie el delimitador / a otra cosa, como s### (puede usar cualquier carácter como delimitador).

use strict; 
use warnings; 
use File::Copy; 

open my $fh, '<', $testSuiteFile or die $!; 
open my $out, '>', $testSuiteFile . ".bak" or die $!; 

while (<$fh>) { 
    s/\Q${localTestDir}\E//g; 
    print $out $_; 
} 

move($testSuiteFile . ".bak", $testSuiteFile) or die $!; 

O utilice Tie::File

use strict; 
use warnings; 
use Tie::File; 

tie, my @file, 'Tie::File', $testSuiteFile or die $!; 

for (@file) { 
     s/\Q${localTestDir}\E//g; 
} 
untie @file; 
+0

¡Me encanta la solución Perl! – Dave

+1

@Dave Perl es muy amable;) las llamadas al sistema pueden ser útiles, pero casi siempre es preferible utilizar IMO perl puro. – TLP

6

Parece que $localTestDir ha comenzado con .

Remedio cambiando el delimitador de expresión regular para algo que no sea /:

my $searchAndReplaceCmd = "perl -pi -e 's!\\Q${localTestDir}\\E!!g' ${testSuiteFile}"; 

De perldoc perlrequick:

$x = "A 39% hit rate"; 
$x =~ s!(\d+)%!$1/100!e;  # $x contains "A 0.39 hit rate" 

El último ejemplo muestra que s/// pueden utilizar otros delimitadores, tales como s!!! y s{}{}, e incluso s{}//. Si se utilizan comillas simples s''', entonces la expresión regular y el reemplazo se tratan como cadenas de comillas simples.

+1

pero ¿qué pasa si '$ localTestDir' contiene un'! '? – ErikR

+0

@ user5402: Mire el ejemplo en 'perlrequick', use otro delimitador:' s ### ',' s ,,, ',' s <><> ',' s {} // ', etc. – Zaid

+0

mi punto es que tienes que elegir un delimitador antes de saber qué '$ localTestDir' es. ¿Qué ocurre si '$ localTestDir' contiene todos los caracteres ASCII? ¿Ahora que haces? – ErikR

1

Cambiar los delimitadores es útil, pero en general puede poner una barra invertida delante de cualquier carácter de expresión regular para que no sea especial.

Así s/\/abc/\/xyz/funcionará, aunque no es muy legible.

+1

alias 'leaning-toothpick-syndrome' :) – Zaid

0

El problema es que la sustitución de $localTestDir está ocurriendo demasiado pronto.

Aquí es un método que le permite utilizar / para su re-delimitadores:

system('perl', '-pi', 
     '-e', 'BEGIN { $dir = shift(@ARGV) };', 
     '-e', 's/\\Q$dir\\E//g', 
     $localTestDir, 
     $suiteTestFile 
); 

Tenga en cuenta que esto también protege el contenido de $suiteTestFile sean interpretados por el shell.

Cuestiones relacionadas