file - que - archivo dividido en la enésima aparición de delimitador
que es un delimitador en programacion (3)
¿Hay un trazador de líneas para dividir un archivo de texto en pedazos / trozos después de cada enésima ocurrencia de un delimitador?
ejemplo: el delimitador a continuación es "+"
entry 1
some more
+
entry 2
some more
even more
+
entry 3
some more
+
entry 4
some more
+
...
Hay varios millones de entradas, por lo que dividir en cada aparición de delimitador "+" es una mala idea. Quiero dividir, por ejemplo, cada instancia 50,000 del delimitador "+".
Los comandos de Unix "split" y "csplit" simplemente no parecen hacer esto ...
No es muy difícil hacerlo en Perl si no puedes encontrar una alternativa adecuada (y funcionará bastante bien):
#!/usr/bin/env perl
use strict;
use warnings;
# Configuration items - could be set by argument handling
my $prefix = "rs."; # File prefix
my $number = 1; # First file number
my $width = 4; # Number of digits to use in file name
my $rx = qr/^/+$/; # Match regex
my $limit = 3; # 50,000 in real case
my $quiet = 0; # Set to 1 to suppress file names
sub next_file
{
my $name = sprintf("%s%.*d", $prefix, $width, $number++);
open my $fh, ''>'', $name or die "Failed to open $name for writing";
print "$name/n" unless $quiet;
return $fh;
}
my $fh = next_file; # Output file handle
my $counter = 0; # Match counter
while (<>)
{
print $fh $_;
$counter++ if (m/$rx/);
if ($counter >= $limit)
{
close $fh;
$fh = next_file;
$counter = 0;
}
}
close $fh;
Eso está lejos de ser un trazador de líneas; No estoy seguro de si eso es un mérito o no. Los elementos que deben configurarse se agrupan y pueden configurarse mediante opciones de línea de comando, por ejemplo. Podría terminar con un archivo vacío; usted podría detectar eso y eliminarlo si es necesario. Necesitarías un segundo contador; el existente es un "contador de coincidencias" pero también necesitarías un contador de línea, y si el contador de línea fuera cero en ese momento, eliminarías el último archivo. También necesitarías el nombre para poder eliminarlo ... difícilmente, pero no difícil.
Dar la entrada (básicamente dos copias de sus datos de muestra), la salida de repsplit.pl
(repetir división) fue como se muestra:
$ perl repsplit.pl data
rs.0001
rs.0002
rs.0003
$ cat data
entry 1
some more
+
entry 2
some more
even more
+
entry 3
some more
+
entry 4
some more
+
entry 1
some more
+
entry 2
some more
even more
+
entry 3
some more
+
entry 4
some more
+
$ cat rs.0001
entry 1
some more
+
entry 2
some more
even more
+
entry 3
some more
+
$ cat rs.0002
entry 4
some more
+
entry 1
some more
+
entry 2
some more
even more
+
$ cat rs.0003
entry 3
some more
+
entry 4
some more
+
$
Usando perl y +
como separador de entrada en un "trazador de líneas" conciso:
Si desea hacer $_ > newprefix.part.$c
como se indica en su comentario:
$ limit=50000 perl -053 -Mautodie -lne ''
BEGIN{$/=""}
$count++;
if ($count >= $ENV{limit}) {
open my $fh, ">", "newprefix.part.$c";
print $fh $_;
close $fh;
}
'' file.txt
$ ls -l newprefix.part.*
Doc
Usando awk
puedes:
awk ''/^/+$/ { delim++ } { file = sprintf("chunk%s.txt", int(delim / 50000)); print >> file; }'' < input.txt
Actualizar:
Para no incluir el delimitador, intente esto:
awk ''/^/+$/ { if(++delim % 50000 == 0) { next } } { file = sprintf("chunk%s.txt", int(delim / 50000)); print > file; }'' < input.txt
La next
palabra clave hace que awk pare las reglas de procesamiento para este registro y avance a la siguiente (línea). También cambié el >>
a >
ya que si lo ejecuta más de una vez, probablemente no quiera agregar los viejos archivos de fragmentos.