Как «дополнить» строку переменной длины для выравнивания последнего столбца - PullRequest
11 голосов
/ 03 октября 2009

У меня есть вход в следующем формате:


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

Я могу легко извлечь эти отдельные поля с помощью регулярного выражения /(\S+)\s+(\S+)\s+(\S+)\s+/. Я назвал их $time, $name и $number. Моя проблема в том, что я хочу отобразить это так, чтобы $number выровнялся идеально. Поскольку $name может быть любой длины, что является лучшим решением для этого?

Я бы хотел, чтобы вывод выглядел следующим образом. Обратите внимание, что мне пришлось использовать точки, чтобы выровнять последнее поле, так как я не смог использовать пробел для этого, не знаю почему 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

Я думал о том, чтобы поместить $name в массив. А затем используйте функцию, чтобы найти ту, у которой наибольшее количество символов. Наконец, я бы выбрал более короткое имя, чтобы оно соответствовало самому длинному имени. Есть ли лучший и более эффективный способ сделать это?

Ответы [ 6 ]

20 голосов
/ 03 октября 2009

Для форматирования попробуйте использовать функцию sprintf , как в

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

(знак минус означает выравнивание по левому краю)

4 голосов
/ 03 октября 2009

Это было дано кем-то здесь :

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;

Вы можете изменить имена переменных, и это должно работать для вас.

3 голосов
/ 03 октября 2009

Посмотрите на Perl6 :: Форма .

Это рекомендуемый подход к использованию формата . См. Этот предыдущий ответ о переполнении стека: Какие другие языки имеют функции и / или библиотеки, подобные формату Perl?

Вот пример того, как Perl6 :: Form делает то, что вы хотите с вашими данными:

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. Если ваши поля данных станут больше, чем указанные поля формы, вы столкнетесь с проблемами форматирования (и то же самое относится и к решениям sprintf и форматирования).

Это легко исправить в зависимости от ваших требований к выходу. Например, если вы хотите сохранить стабильность таблицы, тогда ...

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

... будет заключать в слова каждый столбец для вас.

2 голосов
/ 03 октября 2009

Если вы не знаете максимальную ширину среднего поля, вам придется сделать два прохода по данным, как @ 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
0 голосов
/ 20 декабря 2013
      $lineLength = length($line1);
      write;
}
close FD1;

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

Итак, в приведенном выше примере «$ lineLength» сдвигается вправо с начальными пробелами.

0 голосов
/ 03 октября 2009

Что бы вы ни делали, вам придется делать два прохода - один для определения длины, другой для печати, используя эту длину в форматировании. Я бы пошел с ответом sprintf, уже предоставленным для форматирования, лично, просто меняя число в нем.

То, как вы выполняете эти два прохода, скорее зависит от того, откуда поступают данные - чтение файла дважды может быть разумнее, чем предварительная обработка в памяти, если файл огромен, но предложенное вами решение для массива звучит хорошо для меня .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...