2009-04-22 23 views
6

¿Cómo puedo hacer esto?¿Cómo puedo omitir líneas al sorber un archivo en Perl?

open FILE, $somefile; 
foreach (<FILE>) 
{ 
    if (/some_regex/) 
    { 
     $want_the_next_line = <FILE>; 
     $want_the_next_line_after_that = <FILE>; 
    } 
} 

¿Sabe a qué me refiero? Básicamente quiero sorber un montón de líneas en medio de mi foreach, en lugar de tener que recordar mi estado y verificarlo cada vez que repito. Y actualmente no puedo encontrar nada útil en <> en Perldoc.

Ah, y por cierto, realmente no quieren:

@file = <FILE>; 

estoy seguro de entender.

+0

No entiendo. A menos que tal vez haya querido decir, no foreach, está leyendo todo el archivo de todos modos, si hay un problema de memoria. – ysth

+0

Sí, me refiero a foreach, y como usted menciona && David dice a continuación, estaba leyendo todo el archivo como una matriz de todos modos, que es exactamente lo que no quería. – Joe

Respuesta

11

Uso while en lugar de foreach:

open FILE, $somefile; 
while (<FILE>)      # <<-- HERE 
{ 
    if (/some_regex/) 
    { 
     $want_the_next_line = <FILE>; 
     $want_the_next_line_after_that = <FILE>; 
    } 
} 

El bucle while sólo se lee una sola línea de <FILE> y, a continuación, puede hacer lo que quiera con él en la iteración actual.

También esta técnica te ayudará a evitar leer todo el archivo a la vez.

técnico:foreach() requiere una matriz, por lo tanto, la lectura en todo el archivo a la vez, mientras que la expresión en el bucle es while() contexto escalar y sólo está marcada por los valores "falsos", como la que se produce EOF.

+0

Ya sabes, me había olvidado totalmente de eso. Gracias Señor. Tu rock ¿Pero qué haces hasta tan tarde?: D – Joe

+2

Son las 9:35 am aquí en Europa. Bienvenido a la globalización. –

+2

+1. Una advertencia: a diferencia de foreach, mientras que clobbers $ _, entonces probablemente quieras "local $ _;" antemano. –

5

Puede utilizar las mismas técnicas en perlfaq5: ¿Cómo cambio, supresión o inserción en una línea en un archivo o agregar en el inicio de un archivo ?:


(aportado por Brian D foy)

La idea básica de insertar, cambiar o eliminar una línea de un archivo de texto implica leer e imprimir el archivo hasta el punto donde desea realizar el cambio, realizar el cambio, luego leer e imprimir el resto del archivo. Perl no proporciona acceso aleatorio a las líneas (especialmente porque el separador de entrada de registro, $ /, es mutable), aunque módulos como Tie :: File pueden simularlo.

programa A Perl para hacer estas tareas toma la forma básica de la apertura de un archivo, imprimir sus líneas, a continuación, cierre el archivo:

open my $in, '<', $file  or die "Can't read old file: $!"; 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

while(<$in>) 
    { 
    print $out $_; 
    } 

    close $out; 

Dentro de esa forma básica, añadir las piezas que usted necesita para insertar, cambiar o eliminar líneas

Para anteponer las líneas al principio, imprima esas líneas antes de ingresar al ciclo que imprime las líneas existentes.

open my $in, '<', $file  or die "Can't read old file: $!"; 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

print $out "# Add this line to the top\n"; # <--- HERE'S THE MAGIC 

while(<$in>) 
    { 
    print $out $_; 
    } 

    close $out; 

Para cambiar las líneas existentes, inserte el código para modificar las líneas dentro del ciclo while. En este caso, el código encuentra todas las versiones en minúscula de "perl" y las mayúsculas. ¡Sucede en cada línea, así que asegúrese de hacer eso en todas las líneas!

open my $in, '<', $file  or die "Can't read old file: $!"; 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

print $out "# Add this line to the top\n"; 

while(<$in>) 
    { 
    s/\b(perl)\b/Perl/g; 
    print $out $_; 
    } 

    close $out; 

Para cambiar solo una línea en particular, el número de línea de entrada, $., Es útil. Primero lea e imprima las líneas hasta la que desea cambiar. A continuación, lea la única línea que desea cambiar, cámbiela e imprímala.Después de eso, lea el resto de las líneas e imprímalas:

while(<$in>) # print the lines before the change 
    { 
    print $out $_; 
    last if $. == 4; # line number before change 
    } 

my $line = <$in>; 
$line =~ s/\b(perl)\b/Perl/g; 
print $out $line; 

while(<$in>) # print the rest of the lines 
    { 
    print $out $_; 
    } 

Para saltear líneas, use los controles de bucle. El siguiente en este ejemplo omite las líneas de comentario, y el último detiene todo el procesamiento una vez que encuentra END o DATA.

while(<$in>) 
    { 
    next if /^\s+#/;    # skip comment lines 
    last if /^__(END|DATA)__$/; # stop at end of code marker 
    print $out $_; 
    } 

hacer el mismo tipo de cosas para eliminar una línea en particular mediante el uso junto a saltar las líneas que no desea que aparezca en la salida. Este ejemplo se salta cada cinco líneas:

while(<$in>) 
    { 
    next unless $. % 5; 
    print $out $_; 
    } 

Si, por alguna extraña razón, que realmente quiere ver todo el archivo a la vez en lugar de procesar línea por línea, puede sorber en (siempre y cuando usted puede caber todo esto en memoria):

open my $in, '<', $file  or die "Can't read old file: $!" 
open my $out, '>', "$file.new" or die "Can't write new file: $!"; 

my @lines = do { local $/; <$in> }; # slurp! 

    # do your magic here 

print $out @lines; 

módulos tales como File :: Slurp y corbata :: archivos puede ayudar con eso también. Si puede, sin embargo, evite leer todo el archivo a la vez. Perl no devolverá esa memoria al sistema operativo hasta que el proceso finalice.

También puede usar uniones Perl para modificar un archivo en el lugar. Lo siguiente cambia todo 'Fred' a 'Barney' en inFile.txt, sobrescribiendo el archivo con los nuevos contenidos. Con el modificador -p, Perl enrolla un ciclo while alrededor del código que especifique con -e, y -i activa la edición in situ. La línea actual está en $ . Con -p, Perl imprime automáticamente el valor de $ al final del ciclo. Ver perlrun para más detalles.

perl -pi -e 's/Fred/Barney/' inFile.txt 

Para realizar una copia de seguridad de inFile.txt, dar extensión de archivo -ia añadir:

perl -pi.bak -e 's/Fred/Barney/' inFile.txt 

Para cambiar sólo la quinta línea, se puede añadir un $ que controla la prueba, la línea de entrada. número, entonces sólo realizar la operación cuando pasa la prueba:

perl -pi -e 's/Fred/Barney/ if $. == 5' inFile.txt 

Para agregar líneas antes de una determinada línea, se puede añadir una línea antes de Perl imprime _ $ (o líneas!):

perl -pi -e 'print "Put before third line\n" if $. == 3' inFile.txt 

Usted puede incluso agregar una línea al comienzo de un archivo, ya que las impresiones de la línea de corriente al final del bucle:

perl -pi -e 'print "Put before first line\n" if $. == 1' inFile.txt 

Para insertar una línea después de que uno ya está en el archivo, el uso el -n cambiar. Es como -p excepto que no imprime $ _ al final del ciclo, por lo que debe hacerlo usted mismo. En este caso, imprima $ _ primero, luego imprima la línea que desea agregar.

perl -ni -e 'print; print "Put after fifth line\n" if $. == 5' inFile.txt 

Para eliminar líneas, solo imprima las que desee.

perl -ni -e 'print unless /d/' inFile.txt 

    ... or ... 

perl -pi -e 'next unless /d/' inFile.txt 
Cuestiones relacionadas