2009-10-02 5 views
10

Tengo una entrada del siguiente formato:Cómo "rellenar" una cadena de longitud variable tenga un alineado última columna


09:08:11  XXXXXXXXXXXXX 1.1.1.1   
09:09:03  YYYYYYYY 2.2.2.2   
09:12:37  ZZZZ 3.3.3.3 

soy capaz de extraer estos campos particulares fácilmente usando la expresión regular /(\S+)\s+(\S+)\s+(\S+)\s+/. Los llamé $time, $name y $number. Mi problema es que quiero mostrar esto para que el $number se alinee perfectamente. Como el $name puede ser de cualquier longitud, ¿cuál es la mejor solución para esto?

Me gustaría que la salida se vea así. Tenga en cuenta que tuve que usar puntos para alinear el último campo, ya que no pude usar la barra espaciadora para hacer esto, no estoy seguro de por qué. Anyhoo.


09:08:11  XXXXXXXXXXXXX 1.1.1.1   
09:09:03  YYYYYYYY   2.2.2.2   
09:12:37  ZZZZ    3.3.3.3 

pensé en poner el $name en una matriz. Y luego use una función para encontrar el que tenga el número de caracteres más largo. Finalmente rellenaría el nombre más corto para que coincida con el nombre más largo. ¿Hay una manera mejor y más eficiente de hacer esto?

+0

Utilice la opción de formato de código para especificar que se debe usar la fuente de ancho fijo y el preformateado. :) – Amber

+0

Estaba haciendo esta edición en mi teléfono, hasta que me di cuenta de que era demasiado difícil. –

+0

¿Los números son siempre de un dígito cada uno? Si no, ¿qué quieres hacer? –

Respuesta

19

para el formateo, intente utilizar la función sprintf, como en

$line = sprintf "%-12s %-20s %-s\n", $time, $name, $number; 

(significa el signo menos Justifica a la izquierda)

+0

gracias! Esto es exactamente lo que estaba buscando. – qdog

4

fue dado por alguien here:

my($name, $telephone, $stime); 

format Infos = 
@<<<<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<<<<<<@<<<<<<<<<<<<<<< 
$name,    $telephone,   $stime 
. 

$~ = 'Infos'; 

($name, $telephone, $stime) = ('Name:', 'Telephone:', 'Start Time:'); 
write; 

($name, $telephone, $stime) = ('Mike Bax', 'tel-41596', 'Fri 8/22 13:31'); 
write; 

Puede cambiar los nombres de las variables, y debería funcionar para usted.

+3

Guau, la gente todavía usa formatos? ¿Qué tan perl 4 de ustedes :) – Ether

0

lo que hagas, vas a tener que ver con dos pases - uno para encontrar la longitud, uno para imprimir, usando esa longitud en el formateo. Me gustaría ir con la respuesta sprintf ya dada para el formato, personalmente, simplemente variando el número en él.

Exactamente cómo lo hace las dos pasadas más bien depende de dónde provienen los datos - leer un archivo dos veces podría ser más inteligente que preprocesarlo en la memoria si el archivo es enorme, pero la solución de matriz que está proponiendo suena bien para yo.

2

Si no conoce el ancho máximo del campo intermedio, tendrá que hacer dos pasadas sobre los datos como @ijw notes.

#!/usr/bin/perl 

use strict; 
use warnings; 

use Fcntl qw(:seek); 

my $max_length = 0; 
my $data_pos = tell DATA; 

while (my $line = <DATA>) { 
    last unless $line =~ /\S/; 
    my $name = (split ' ', $line)[1]; 
    my $name_length = length $name; 
    $max_length = $name_length if $name_length > $max_length; 
} 

seek DATA, $data_pos, SEEK_SET; 

while (my $line = <DATA>) { 
    last unless $line =~ /\S/; 
    my ($date, $name, $ip) = split ' ', $line; 
    printf "%s %-${max_length}s %s\n", $date, $name, $ip; 
} 

__DATA__ 
09:08:11  XXXXXXXXXXXXX 1.1.1.1 
09:09:03  YYYYYYYY 2.2.2.2 
09:12:37  ZZZZ 3.3.3.3 
3

Eche un vistazo a Perl6::Form.

Este es el enfoque recomendado sobre el uso de format.Ver este anterior Pila   respuesta de desbordamiento: What other languages have features and/or libraries similar to Perl's format?

Aquí es un ejemplo de Perl6 :: Formulario de hacer precisamente lo que quiera con sus datos:

use Perl6::Form; 

my ($time, $name, $number); 

my @data = (
    [ qw(09:08:11 XXXXXXXXXXXXX 1.1.1.1) ], 
    [ qw(09:09:03 YYYYYYYY 2.2.2.2)  ], 
    [ qw(09:12:37 ZZZZ 3.3.3.3)   ], 
); 

for my $line (@data) { 
    push @$time, $line->[0]; 
    push @$name, $line->[1]; 
    push @$number, $line->[2]; 
} 

print form 
    '{[[[[[[} {[[[[[[[[[[[[[[[[[[[[} {[[[[[[}', 
    $time,  $name,     $number; 


NB. Si sus campos de datos llegan a ser más grandes que los campos de formulario especificados, se encontrará con problemas de formato (y lo mismo se aplica a sprintf y soluciones de formato).

Es fácil de arreglar dependiendo de cuáles sean sus requisitos de salida. Por ejemplo, si desea mantener la estabilidad tabular, entonces ...

print form { layout => 'tabular' }, 
    '{[[[[[[} {[[[[[[[[[[[[[[[[[[[[} {[[[[[[}', 
    $time,  $name,     $number; 

... ajustará la palabra para cada columna.

0
 $lineLength = length($line1); 
     write; 
} 
close FD1; 

format STDOUT = 
@>>>>> @* 
$lineLength,$line1 
. 
; 

Por lo tanto, en el ejemplo anterior, "$ lineLength" se empuja hacia la derecha con espacios iniciales.

Cuestiones relacionadas