我正在分解文本文件,并将其设置为新文件。代码有效,但我知道格式没有正确排列,因为我是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;
答案 0 :(得分:1)
我不确定我是否完全理解这个问题,如果需要请澄清。
正在打印的字段的宽度可以由printf控制,或者您可以按sprintf形成所需长度的字符串。
为了使整个输出很好地排列,你首先需要找到每列中最长字符串的长度,或者至少是最长的字符串长度。由于您一次打印一行,因此您显示的内容不太可能。
my $maxlen = '...'; # decide on or precompute the maximum field width
my $printToFile = join ' | ',
map { sprintf "%${maxlen}s", $_ } @finalElementLine;
map格式化每个元素的长度为$maxlen
的字符串,并根据需要用空格填充每个元素。它返回该列表,然后通过问题中使用的内容将join转换为标量。
如果您想在左侧排列它们,请使用sprintf "%-${maxlen}s", $_
。我使用s
转换(对于字符串),因为没有给出详细信息。请参阅文档并根据需要进行调整。
为了可靠地估计最大字段宽度,您需要首先拥有所有行。如果没有太多数据,您可以将每个已处理的行存储为数组中的arrayref并在末尾进行打印。通过其他简化
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;
这将打印出具有相同宽度的所有字段。如果某些比非最佳的其他更长,则在这种情况下为每列分别设置字段宽度,并在打印时使用它。这使得打印相当混乱,所以只在必要时才这样做。由于我没有您的数据,因此尚未经过测试,请详细说明。
一些评论
将数组分配给标量时,标量获取数组元素的数量
$counter
未使用,因此我删除了它。要恢复:my $counter = @tokens;
grep
中的条件可以使用正则表达式缩短
每一行(@finalElementLine
)都存储在@rows
中作为arrayref
$maxlen
:形成所有行中所有字段的列表,然后取长度,然后取最大值
$rline
的每个元素@rows
被@$rline
解除引用到map
如果实际上不需要$NumOfElements
,整个循环会大大简化
push @rows, [ grep { not /^(?:| )$/ } @tokens ];
如果你可以排除任何数量的空间(而不仅仅是一个),那么请使用
grep { not /^\s*$/ }
不只有空格(或没有) - 或 -
grep { /\S/ }
非空格(至少一个)
如果不需要$numOfElements
,则处理顺序的摘要为
my @rows = map {
my @r = grep { /\S/ } split /\t/;
@r ? \@r : ();
} <$fh>;
虽然这正确地取代了while
循环,但这种挤压很可能不适合生产。
列表上下文中的<$fh>
返回文件中的所有行,map
转换为输出列表,分配给@rows
。在map
选项卡上的每一行都是split
,并且从该列表中筛选出空/仅空格元素。如果()
最终没有元素,则返回refarray,或返回空列表@r
。
map
返回的空列表会被其他元素压缩成一个列表,从而有效地从输出中消失。执行map
工作是grep
的诀窍,过滤掉事情。