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

如何在perl中打印文本文件的行时保持适当的列空间,perl,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 很明显,行中每个项目之间的间距不相等,但它们是以列为基础对齐的。 我想

我试图编辑我的文件的几行,并创建新的文件与所有修改

我的行不是段落格式,它看起来像下面这样

 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  
很明显,行中每个项目之间的间距不相等,但它们是以列为基础对齐的。 我想编辑从XA到XAHBB的R3第三项 但无法保持柱对齐

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
如何在编辑文件时保持列对齐?

这就是它的用途:

#/usr/bin/perl
使用警告;
严格使用;
使用Text::Table;
my$table='Text::table'->新建;
而(){
我的@RowEdit=split';
如果($RowEdit[0]等式'R3'){
$RowEdit[2]。='HBB';
}
$table->add(@RowEdit);
}
打印$table;
打印美元+1、“\n”;
__资料__
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
    可以用于字符串相等-它更容易读取,运行更快
  • 如果未提供任何参数,则使用
    $\uuu
    作为第二个参数。在
    grep
    map
    之外的任何地方键入
    $\ucode>都是一种代码气味——要么是值得命名的东西,要么可以不用它来书写
  • 要附加字符串,可以使用
    =
    运算符

您可以使用
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

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

因为这是Perl最初为()编写的任务之一,那么为了完整性,还应该提到好的ol'plain Perl格式,请参见
man perlform
。例如

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

for my ... (...) {
   # set $col1 .... and then
   write
}
格式标准输出=

@有没有不使用Text::Table扩展就可以做到这一点的方法?使用基本perl命令,您可以随时阅读的源代码-只需单击。
sprintf
format
提供了类似的功能,但它们本质上不是动态的。您必须提前选择列宽(尽管您可能会“检测”列中最宽的单元格,并使用它),我正在将此数据从文件中打印到其他文件。will
sprintf
解决方案使用此场景@Sobrique
#!/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
format STDOUT =
@<<<<< @ @<<<<, ....
$col1, $col2, $col3, ...
.

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