2010-05-17 8 views
7

Tengo un archivo de la siguiente manera:Partido a través de múltiples líneas de expresión regular de perl

01 00 01 14 c0 00 01 10 01 00 00 16 00 00 00 64 
00 00 00 65 00 00 01 07 40 00 00 22 68 61 6c 2e 
6f 70 65 6e 65 74 2e 63 6f 6d 3b 30 30 30 30 30 
30 30 30 32 3b 30 00 00 00 00 01 08 40 00 00 1e 
68 61 6c 2e 6f 70 65 6e 65 74 2d 74 65 6c 65 63 
6f 6d 2e 6c 61 6e 00 00 00 00 01 28 40 00 00 21 
72 65 61 6c 6d 31 2e 6f 70 65 6e 65 74 2d 74 65 
6c 65 63 6f 6d 2e 6c 61 6e 00 00 00 00 00 01 25 
40 00 00 1e 68 61 6c 2e 6f 70 65 6e 65 74 2d 74 
65 6c 65 63 6f 6d 2e 6c 61 6e 00 00 00 00 01 1b 
40 00 00 20 72 65 61 6c 6d 2e 6f 70 65 6e 65 74 
2d 74 65 6c 65 63 6f 6d 2e 6c 61 6e 00 00 01 02 
40 00 00 0c 01 00 00 16 00 00 01 a0 40 00 00 0c 
00 00 00 01 00 00 01 9f 40 00 00 0c 00 00 00 00 
00 00 01 16 40 00 00 0c 00 00 00 00 00 00 01 bb 
40 00 00 28 00 00 01 c2 40 00 00 0c 00 00 00 00 
00 00 01 bc 40 00 00 13 31 39 37 37 31 31 31 32 
32 33 31 00 

Estoy leyendo el archivo y luego encontrar ciertos octetos y reemplazándolos con etiquetas:

while(<FH>){ 
    $line =~ s/(00 00 00 64)/<incr4> /g; 
    $line =~ s/(00 00 00 65)/<incr4> /g; 
    $line =~ s/(30 30 30 30 30 32)/<incr6ascii:999999:0>/g; 
    $line =~ s/(31 31 32 32 33 31)/<incr6ascii:999999:0>/g; 
    print OUTPUT $line; 
} 

Así, por ejemplo, , 00 00 00 64 sería reemplazado por la etiqueta <incr4>. Esto funcionaba bien, pero parece que ya no puede coincidir en varias líneas. Por ejemplo, el patrón 31 31 32 32 33 31 se ejecuta en varias líneas, y la expresión regular no parece captarlo. Traté de usar modificadores de patrón/m/s para ignorar nuevas líneas pero tampoco coinciden. La única manera de evitar que puedo llegar a, es leer todo el archivo en una cadena usando:

undef $/; 
my $whole_file = <FH>; 
my $line = $whole_file; 
$line =~ s/(00 00 00 64)/<incr4> /g; 
$line =~ s/(00 00 00 65)/<incr4> /g; 
$line =~ s/(30 30 30 30 30 32)/<incr6ascii:999999:0>/g; 
$line =~ s/(31 31 32 32 33 31)/<incr6ascii:999999:0>/g; 
print OUTPUT $line; 

Esto funciona, las etiquetas se insertan correctamente, pero la estructura del archivo se altera radicalmente. Todo se descarta en una sola línea. Me gustaría conservar la estructura del archivo tal como aparece aquí. ¿Alguna idea de cómo podría hacer esto?

/John

Respuesta

4

El truco aquí es para que coincida con la clase de todo el espacio que los caracteres de \s:

my $file = do {local (@ARGV, $/) = 'filename.txt'; <>}; # slurp file 

my %tr = ( # setup a translation table 
    '00 00 00 64'  => '<incr4>', 
    '00 00 00 65'  => '<incr4>', 
    '00 30 30 30 30 32' => '<incr6ascii:999999:0>', 
    '31 31 32 32 33 31' => '<incr6ascii:999999:0>', 
); 

for (keys %tr) { 
    my $re = join '\s+' => split; # construct new regex 

    $file =~ s{($re)}{ 
     $1 =~ /\n/ ? "\n$tr{$_}" : $tr{$_} # if octets contained \n, add \n 
    }ge # match multiple times, execute the replacement block as perl code 
} 
print $file; 
+0

Excelente! Funciona perfectamente ... ¡Nunca pensé en usar un mapa hash, una solución ingeniosa! – John

+1

+1: ¡Gran solución, simplemente ponga el modificador '/ x' al final! – Zaid

Cuestiones relacionadas