2017-01-12 1 views
1

Ich zerlege eine Textdatei und setze sie auf eine neue. Der Code funktioniert, aber ich weiß, dass das Format nicht richtig ausgerichtet ist, weil ich neu bei Perl bin - und eine Google-Suche scheint nicht zu funktionieren. Können Sie die einzelnen Feldlängen Ihres Arrays einstellen, nachdem Sie das Array erstellt haben?Wie legen Sie eine Länge fest und rechtfertigen ein Array-Feld in Perl?

while (my $line = <INFILE1>) 
{ 
    chomp $line; 
    my @tokens = split /\t/, $line; 
    $numOfElements = 0; 
    $counter = 0; 
    foreach $element (@tokens) 
    { 
     $counter = $counter + 1; 
    } 

foreach $element (@tokens) 
{ 

    if ($element eq "" or $element eq " ") 
    { 

    } 
    else 
    { 
     push @shiftedElements, $element; 

     $numOfElements = $numOfElements + 1; 

    } 



} 


my @finalElementLine = ($numOfElements);#used to prevent array size` from not matching up with the elements in the new array 
    push @finalElementLine, @shiftedElements;#fills the new array 
    $printToFile = " $finalElementLine[1] | $finalElementLine[2] | $finalElementLine[$numOfElements] | $finalElementLine[$numOfElements-4] | $finalElementLine[$numOfElements-3] | $finalElementLine[$numOfElements-2] $finalElementLine[$numOfElements-1]\n"; 




    my $OUTFILE;   
    open $OUTFILE, '>>', $newFile; 
    print { $OUTFILE } $printToFile; 
    close $OUTFILE; 
+1

Ich verstehe nicht ganz das Ziel - die Ausgabe zu richten? Was bedeutet das: "_prevent Array-Größe von nicht mit den Elementen in dem neuen Array_ überein?"? Kannst du die gewünschte Ausgabe posten, wenn das die Frage ist? – zdim

+0

Die Ausgabe muss angezeigt werden, wenn Sie die TXT-Datei öffnen. Es muss sich mit den Säulen decken, die eine vorherbestimmte Länge haben müssen. Der Kommentar im Code war für den anderen Programmierer, um zu wissen, dass jedes Array von Elementen eine maximale Länge von Elementen hatte, so dass wir uns später darauf beziehen konnten. –

Antwort

1

Ich bin mir nicht sicher, ob ich die Frage vollständig verstehe, bitte klären Sie, wenn nötig.

Die Breite eines Feldes, das gedruckt wird, kann durch printf gesteuert werden, oder Sie können eine Zeichenfolge der gewünschten Länge von sprintf bilden.

Damit die gesamte Ausgabe gut ausgerichtet ist, müssen Sie zuerst die Länge der längsten Zeichenfolge in jeder Spalte finden, oder zumindest die längste überhaupt. Das ist in dem, was Sie anzeigen, nicht möglich, da Sie jeweils eine Zeile drucken.

my $maxlen = '...'; # decide on or precompute the maximum field width 

my $printToFile = join ' | ', 
    map { sprintf "%${maxlen}s", $_ } @finalElementLine; 

Die map formatiert eine Zeichenkette der Länge $maxlen von jedem Element, die jeweils durch Klotzen mit Leerzeichen nach Bedarf. Sie gibt diese Liste zurück, die dann in einen Skalar von join -ed wird, was in der Frage verwendet wird.

Wenn Sie sie auf der linken Seite ausrichten möchten, verwenden Sie sprintf "%-${maxlen}s", $_. Ich verwende die s Konvertierung (für eine Zeichenfolge), da keine Details angegeben sind. Siehe die Dokumentation und passen Sie sie gegebenenfalls an.

Um die maximale Feldbreite zuverlässig zu schätzen, müssen Sie zuerst alle Zeilen haben. Wenn nicht zu viele Daten vorhanden sind, können Sie jede verarbeitete Zeile als Arrayref in einem Array speichern und am Ende drucken. Mit anderen Vereinfachungen

use warnings; 
use strict; 
use List::Util qw(max); 

my $file = '...'; 
open my $fh, '<', $file or die "Can't open $file: $!"; 

while (my $line = <$fh>) 
{ 
    chomp $line; 
    my @tokens = split /\t/, $line; 

    # Run the explicit loop if other processing is needed, or: 
    my @shiftedElements = grep { $_ ne '' and $_ ne ' ' } @tokens; 
    my $numOfElements = @shiftedElements; 

    # UNCLEAR -- is the first element below necessary? 
    # "used to prevent array size from 
    # not matching up with the elements in the new array" 
    my @finalElementLine = ($numOfElements, @shiftedElements); 

    push @rows, \@finalElementLine; 
} 
close $fh; 

my $maxlen = max map { length } map { @$_ } @rows; # for all fields in all rows 

open my $OUTFILE, '>>', $newFile or die "Can't open for appending: $!"; 
foreach my $rline (@rows) 
{ 
    my $printToFile = join ' | ', 
     map { sprintf "%${maxlen}", $_ } @$rline; 
    print $OUTFILE $printToFile, "\n"; 
} 
close $OUTFILE; 

Dieser druckt alle Felder mit der gleichen Breite. Wenn einige länger als andere sind, ist das nicht optimal. In diesem Fall setzen Sie die Feldbreiten separat für für jede Spalte und verwenden Sie diese beim Drucken. Das macht den Druck ein bisschen unordentlicher, also nur wenn es nötig ist. Dies wurde nicht getestet, da ich Ihre Daten nicht habe, bitte erarbeiten Sie mögliche Details.

Einige Kommentare

  • Wenn ein Array mit einem Skalar zugeordnet ist, wird die skalare die Anzahl der Array-Elemente

  • $counter nicht so entfernt es ich verwendet wird.Zur Wiederherstellung: my $counter = @tokens;

  • Die Bedingung in grep kann verkürzt werden regex

  • Jede Zeile (@finalElementLine) in @rows als ArrayRef gespeichert

  • $maxlen: bilden eine Liste aller Felder in allen Reihen, dann nehmen Sie ihre Längen, dann nehmen Sie Maximum davon

  • Jedes Element $rline von @rows ist dereferenced von @$rline in eine Liste für map

  • Wenn $NumOfElements ist eigentlich nicht benötigt, um die gesamte Schleife

    push @rows, [ grep { not /^(?:|)$/ } @tokens ]; 
    
  • stark vereinfacht Wenn Sie jede Menge Raum ausschließen (und nicht nur ein einzeln), dann
    grep { not /^\s*$/ }   nicht nur Leerzeichen (oder nichts)   – ODER –
    grep { /\S/ }                 ein nicht-Raum (mindestens eine)


Wenn $numOfElements nicht notwendig ist, wird eine Zusammenfassung der Verarbeitungssequenz

my @rows = map { 
    my @r = grep { /\S/ } split /\t/; 
    @r ? \@r :(); 
} <$fh>; 

Während dies richtig ersetzt t er while Schleife, so ein Squeeze ist wahrscheinlich ungeeignet für die Produktion.

Der <$fh> im Listenkontext gibt alle Zeilen aus der Datei zurück, die map in eine Ausgabeliste umwandelt, die @rows zugewiesen ist. In map ist jede Zeile split auf Tab und aus dieser Liste werden leere/space-only Elemente ausgefiltert. Das Refarray wird zurückgegeben, oder eine leere Liste (), wenn @r endete ohne Elemente.

Eine leere Liste in map Rückkehr wird mit anderen Elementen in einer Liste abgeflacht und daher effektiv aus der Ausgabe verschwindet. Es ist map 's Trick zu tun grep' s Job, filter Dinge aus.

+0

Danke! Die Eingabe wird tabulatorgetrennt ausgegeben, muss jedoch aufgereiht, von einem Benutzer neu angeordnet und in eine neue Datei gedruckt werden, in der alles gut und ordentlich angeordnet ist. Vielen Dank! –

Verwandte Themen