2
votes

Comment conserver les espaces de colonne appropriés lors de l'impression des lignes d'un fichier texte en Perl

Ils n'ont manifestement pas un espacement égal entre chaque élément de la ligne, mais ils sont alignés sur la base des colonnes. Je baguette pour éditer le 3e élément de R3 de XA à XAHBB mais impossible de maintenir l'alignement des colonnes

 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

Ma sortie actuelle est comme indiqué ci-dessous

 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

Où, comme mon résultat attendu devrait ressemblez à ceci ci-dessous

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";

Comment maintenir l'alignement des colonnes lors de l'édition d'un fichier?


0 commentaires

3 Réponses :


3
votes

C'est à cela que sert 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

Notez également tous les autres petits changements que j'ai faits:

  • Pas besoin d'utiliser une nouvelle variable pour compter les lignes. Perl a déjà $. .
  • / s change le comportement de . dans une regex. Cela n'a aucun sens de l'utiliser dans une regex qui ne contient pas de point. De plus, eq peut être utilisé pour l'équialité des chaînes s'il n'y a qu'une seule chaîne qui correspond à l'expression régulière - elle est plus facile à lire et plus rapide à exécuter.
  • split utilise $ _ comme deuxième argument si aucun n'est fourni. Taper $ _ n'importe où en dehors de grep ou de map est une odeur de code - soit c'est quelque chose qui vaut un nom, ou peut être écrit sans. li>
  • Pour ajouter une chaîne, vous pouvez utiliser l'opérateur . = .


4 commentaires

y a-t-il un moyen de le faire sans utiliser l'extension Text :: Table? avec des commandes perl basiques


Vous pouvez toujours lire le code source de Text :: Table - il suffit de cliquer sur Source .


sprintf et format vous donnent quelque chose de similaire, mais ils ne sont pas de nature dynamique. Vous devrez choisir vos largeurs de colonne à l'avance (bien que vous puissiez peut-être `` détecter '' quelle serait la cellule la plus large d'une colonne et l'utiliser)


J'imprime ces données d'un fichier vers une autre solution de sprintf fonctionnera avec ce scénario @Sobrique



2
votes

Vous pouvez le faire avec printf () . Mais vous devez faire deux passes sur les données (car il n'y a aucun moyen de savoir quelle est la largeur de colonne la plus large avant d'avoir vu chaque enregistrement de données).

Quelque chose comme ça semble faire l'affaire.

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

Le résultat est:

#!/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

Mais je pense que la solution Text :: Table est meilleure :-)


0 commentaires