Как сохранить правильные пробелы при печати строк текстового файла в Perl - PullRequest
0 голосов
/ 09 января 2019

Я пытаюсь отредактировать несколько строк моего файла и создать новый файл со всеми изменениями

Мои строки не в формате абзаца, это выглядит примерно так ниже

 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 голосов
/ 09 января 2019

Вы можете сделать это с помощью 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 лучше: -)

0 голосов
/ 10 января 2019

Так как это одна из задач, для которой Perl был изначально написан ( Практический язык извлечения и отчетности ), то для полноты также следует упомянуть о хороших старых форматах Perl, см. man perlform. Э.Г.

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

for my ... (...) {
   # set $col1 .... and then
   write
}
0 голосов
/ 09 января 2019

Вот для чего Текст :: Таблица :

#!/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 является запахом кода - либо это что-то стоящее имя, либо может быть написано без него.
  • Чтобы добавить строку, вы можете использовать оператор .=.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...