如何在perl中打印文本文件的行时保持适当的列空间

时间:2019-01-09 08:53:34

标签: perl

我正在尝试编辑文件的几行并创建具有所有修改的新文件

我的行不是段落格式,如下所示,

 R1   X XA  0i  1i   H 0i  
 R2   X XA  1i  1i   H 0i  
 R3   X XA  1i  1i   H 0i  
 R4   X XA  1i  1i   H 0i  
 R5   X XA  1i  1i   H 0i  
 R6   X XA  0i  0i   X 0i  

它们在行中的每个项目之间显然没有相等的间距,但是它们是按列对齐的。 我想将R3第3项从XA编辑为XAHBB 但无法保持列对齐

my $cur_line_num = 1;
while(<Sourcefile>){
            my @RowEdit = split (" ",$_);
               if($RowEdit[0]=~ m/^R3$/s){
                  $RowEdit[2]="RowEdit[2]HBB"
               }
            my $curr_line = join(" ", @RowEdit)
            print $newfile "curr_line\n";
          $cur_line_num++;

}
print "$cur_line_num\n";

我当前的输出如下所示

 R1 X XA 0i 1i H 0i  
 R2 X XA 1i 1i H 0i  
 R3 X XAHBB 1i 1i H 0i  
 R4 X XA 1i 1i H 0i  
 R5 X XA 1i 1i H 0i  
 R6 X XA 0i 0i X 0i

我的预期输出如下所示

 R1   X XA    0i  1i   H 0i  
 R2   X XA    1i  1i   H 0i  
 R3   X XAHBB 1i  1i   H 0i  
 R4   X XA    1i  1i   H 0i  
 R5   X XA    1i  1i   H 0i  
 R6   X XA    0i  0i   X 0i

在编辑文件时如何保持列对齐?

3 个答案:

答案 0 :(得分:3)

这就是Text::Table的作用:

#!/usr/bin/perl
use warnings;
use strict;

use Text::Table;

my $table = 'Text::Table'->new;

while (<DATA>) {
    my @RowEdit = split ' ';
    if ($RowEdit[0] eq 'R3') {
        $RowEdit[2] .= 'HBB';
    }
    $table->add(@RowEdit);
}
print $table;
print $. + 1, "\n";

__DATA__
R1   X XA  0i  1i   H 0i
R2   X XA  1i  1i   H 0i
R3   X XA  1i  1i   H 0i
R4   X XA  1i  1i   H 0i
R5   X XA  1i  1i   H 0i
R6   X XA  0i  0i   X 0i

还请注意我所做的所有其他小更改:

  • 无需使用新变量来计算行数。 Perl已经有了$.
  • /s更改正则表达式中.的行为。在不包含点的正则表达式中使用它是没有意义的。此外,如果只有一个与正则表达式匹配的字符串,则eq可用于字符串等式-更易于阅读和运行。
  • split使用$_作为第二个参数(如果未提供)。在$_grep之外的任何地方键入map都是一种代码味道-它值得一个名字,也可以不用它来编写。
  • 要附加字符串,可以使用.=运算符。

答案 1 :(得分:2)

您可以使用printf()进行此操作。但是您需要对数据进行两次传递(因为在您看到每条数据记录之前,您无法知道最宽的列宽)。

似乎可以解决问题。

#!/usr/bin/perl

use strict;
use warnings;

my @widths; # Store the max widths for each column
my @data;   # Store the actual data

while (<DATA>) {
  my @row;

  # Use the first line to initialise the @widths array
  if ($. == 1) {
    @row = /(\S+\s*)/g;
    @widths = map { length() - 1} @row; # Subtract 1 for gutter
    @row = map { s/\s+$//; $_ } @row;   # Remove trailing whitespace
  } else {
    @row = split;
  }

  # Split the data
  my @row = split;
  # Store the split data
  push @data, \@row;
  # Make the (optional) transformation
  $row[2] .= 'HBB' if $row[0] eq 'R3';

  # Look at each column in this row of data and
  # compare it to the widest data that we've previously
  # seen in that column.
  for my $i (0 .. $#row) {
    $widths[$i] = length $row[$i]
      if length $row[$i] > ($widths[$i] // 0);
  }
}

# Create a printf output format using the column
# widths we've stored in @widths
my $fmt = join ' ', map { "%-${_}s" } @widths;

# Use printf to display each line of data.
printf "$fmt\n", @$_ for @data;

__DATA__
R1   X XA  0i  1i   H 0i
R2   X XA  1i  1i   H 0i
R3   X XA  1i  1i   H 0i
R4   X XA  1i  1i   H 0i
R5   X XA  1i  1i   H 0i
R6   X XA  0i  0i   X 0i

输出为:

R1   X XA    0i  1i   H 0i
R2   X XA    1i  1i   H 0i
R3   X XAHBB 1i  1i   H 0i
R4   X XA    1i  1i   H 0i
R5   X XA    1i  1i   H 0i
R6   X XA    0i  0i   X 0i

但是我认为Text :: Table解决方案更好:-)

答案 2 :(得分:0)

由于这是Perl最初为(Practical Extraction and Reporting Language)编写的任务之一,因此出于完整性考虑,还应提及良好的纯Perl格式,请参见man perlform。例如

format STDOUT =
@<<<<< @ @<<<<, ....
$col1, $col2, $col3, ...
.

for my ... (...) {
   # set $col1 .... and then
   write
}