对齐表中的值

时间:2012-08-15 07:38:17

标签: regex perl

Test.txt
tom 
cat=0  bat=1  mat=0  pen=1
ironman122_bore.1 
cat=8e-7  bat=8.001e-7  mat=5e-6  pen=200.001e-6     
batmanbegin_nice.1  
cat=10  bat=1  mat=0.25  pen=49.25   

这是我输入的一个示例,我希望我的输出与Out.txt

类似
Out.txt
name                cat       bat       mat       pen               
tom                 -         1         -         -    
ironman122_bore.1   8e-7      8.001e-7  5e-6      200.001e-6
batmanbegin_nice.1  10        1         0.25      49.25 

这是我试过的东西

my $pr = "%-12s"; 
my @headers = qw/name cat bat mat pen/; 
my %names; 
while (<DATA>) {     
    chomp;     
    my $line = <DATA>;     
    %{$names{$_}} = split /=|\s+/, $line; 
}  
printf $pr x @headers . "\n", @headers; 
for (keys %names) {     
    my @ds = ($_);     
    for my $k (@headers[1..$#headers]) {
       my $v = $names{$_}->{$k};         
       push @ds, $v ? $v : '-';     
    }     
    printf $pr x @ds . "\n", @ds; 
}

但我得到一个输出

name          cat       bat       mat       pen               
tom        -         1         -         -    
ironman122_bore.1  8e-7      8.001e-7  5e-6      200.001e-6
batmanbegin_nice.1  10         1         0.25     49.25 

如何修改代码以获得Out.txt中显示的对齐输出? 当我使用与我给出的输入相似的实际数据时,我无法实现我的预期。

编辑:示例输入已与预期结果一起更改

3 个答案:

答案 0 :(得分:0)

使用早期数据

发布的代码对我来说很好。

<强>输出

name        a           b           c           d           e           
bobby       60          74.2        8           -           10.25       
tom         10.1        2           300.89      4145        55

您正在以固定宽度查看它的字体吗?


使用新数据

错位的原因是'name'栏下的某些项目超过12个字符(例如'batmanbegin_nice.1'是18个字符长)。

(s)printf不会像原始帖子中那样将字符串截断为12个字符。

要截断,请在.%之间指定12

printf '%.12s', 'batmanbegin_nice.1' ;  # "batmanbegin_"

如果不需要截断,请将字符串长度增加到%20s

对于最大长度的动态检测,这需要另一个问题:)

答案 1 :(得分:0)

#!/usr/bin/env perl

use strict;
use warnings;
use List::MoreUtils qw(uniq);

my $pr = "%-24s";
my @headers = qw/name/;
my %names;
while (<DATA>) {
    chomp;
    s/^\s+//g;
    s/\s+$//g;
    my $line = <DATA>;
    $line =~ s/^\s+//g;
    $line =~ s/\s+$//g;
    %{$names{$_}} = split /\s*=\s*|\s+/, $line;
}
push @headers, uniq sort map { keys %{$names{$_}}; } keys %names;
printf $pr x @headers . "\n", @headers;
for (keys %names) {
    my @ds = ($_);
    for my $k (@headers[1..$#headers]) {
        my $v = $names{$_}->{$k};
        push @ds, defined $v ? $v : '-';
    }
    printf $pr x @ds . "\n", @ds;
}

__DATA__
 tom
cat = 0  bat =1  mat= 0  pen=1
ironman122_core.1
 cat= 8e-7  bat= 8.001e-7  mat= 5e-6  pen= 200.001e-6
batmanbegin_core.1
cat=10  bat = 1  mat= 0.25  pen= 49.25

输出:

name                    bat                     cat                     mat                     pen                     
tom                     1                       0                       0                       1                       
batmanbegin_core.1      1                       10                      0.25                    49.25                   
ironman122_core.1       8.001e-7                8e-7                    5e-6                    200.001e-6  

答案 2 :(得分:0)

使用sprintf填充对齐输出的任何字符串的简单方法。 例如:您希望2个色谱柱的均匀尺寸为20个字符,并带有分离器。您还希望在指定的文本后左对齐并填充右列。没有问题:

print sprintf("# %20s | %-20s #","Column1","Column2")."\n";

会打印:

username@hostname:~$ perl -e 'print sprintf("# %20s | %-20s #","Column1","Column2")."\n";'
#              Column1 | Column2              #