2011-02-06 16 views
8

que tienen una gran cantidad de archivos de texto con los campos de ancho fijo:archivos Parse de ancho fijo

<c>  <c>  <c> 
Dave Thomas 123 Main 
Dan  Anderson 456 Center 
Wilma Rainbow 789 Street 

El resto de los archivos están en un formato similar, donde el <c> marcará el comienzo de una columna, pero tienen varios anchos de columna (desconocidos) &. ¿Cuál es la mejor manera de analizar estos archivos?

He intentado utilizar Text::CSV, pero ya que no hay delimitador Es difícil conseguir un resultado coherente (a menos que esté utilizando el módulo equivocado):

my $csv = Text::CSV->new(); 
$csv->sep_char (' '); 

while (<FILE>){ 
    if ($csv->parse($_)) { 
     my @columns=$csv->fields(); 
     print $columns[1] . "\n"; 
    } 
} 
+1

¿Por qué se opone a la etiqueta de "análisis sintáctico"? Este es un problema de análisis. Que requiera una solución en Perl no significa que no sea un problema de análisis sintáctico. – zwol

+0

porque no quiero una solución general –

+0

tal vez entendí mal ... Pensé que poner "análisis sintáctico" allí aportaría un montón de soluciones que no son relevantes para mi situación (es decir, python, php, etc.). ..thx –

Respuesta

12

Como el usuario 604939 menciona, unpack es la herramienta para campos de ancho fijo. Sin embargo, unpack necesita pasar una plantilla para trabajar. Puesto que usted dice sus campos pueden cambiar el ancho, la solución es la construcción de esta plantilla de la primera línea del archivo:

my @template = map {'A'.length}  # convert each to 'A##' 
       <DATA> =~ /(\S+\s*)/g; # split first line into segments 
$template[-1] = 'A*';     # set the last segment to be slurpy 

my $template = "@template"; 
print "template: $template\n"; 

my @data; 
while (<DATA>) { 
    push @data, [unpack $template, $_] 
} 

use Data::Dumper; 

print Dumper \@data; 

__DATA__ 
<c>  <c>  <c> 
Dave Thomas 123 Main 
Dan  Anderson 456 Center 
Wilma Rainbow 789 Street 

que imprime:

 
template: A8 A10 A* 
$VAR1 = [ 
      [ 
      'Dave', 
      'Thomas', 
      '123 Main' 
      ], 
      [ 
      'Dan', 
      'Anderson', 
      '456 Center' 
      ], 
      [ 
      'Wilma', 
      'Rainbow', 
      '789 Street' 
      ] 
     ]; 
+0

@random_months_later_downvoter => me importa decir por qué? –

3

sólo tiene que utilizar la función de Perl unpack. Algo como esto:

while (<FILE>) { 
    my ($first,$last,$street) = unpack("A9A25A50",$_); 

    <Do something ....> 
} 

dentro de la plantilla de desempaquetado, la "A ###", puede poner el ancho del campo para cada A. Hay una variedad de otros formatos que se pueden utilizar para mezclar y coincidir con, es decir, campos enteros, etc ... Si el archivo es de ancho fijo, como archivos de mainframe, entonces este debería ser el más fácil.

+0

que es parte de mi pregunta ... el ancho del campo cambiará dependiendo del archivo que lo alimente. ¿Hay alguna forma de desempaquetar para detectar el ancho del encabezado? –

6

CPAN al rescate!

DataExtract::FixedWidth no solo analiza los archivos de ancho fijo, sino que (basado en POD) parece ser lo suficientemente inteligente como para calcular el ancho de las columnas desde la línea del encabezado por sí mismo.

+0

+1 Respuesta notada :-) –

+0

Por cierto, el autor cuelga aquí en SO de vez en cuando. – DVK

+0

DVK ++ =) gracias! DE: FW también está bien probado con [toneladas de entrada de prueba.] (Http://api.metacpan.org/source/ECARROLL/DataExtract-FixedWidth-0.09/t/data/) –

Cuestiones relacionadas