使用 Perl 在逗号和制表符上拆分文本文件并重新排序列
Splitting a text file on commas and tabs and reordering columns using Perl
我正在尝试使用 Perl 将一些数据重新组织成更有用的格式。当前的数据如下所示:
Code Number
|a,c,2,d,c| 5
|b,d,6,c,b| 2
|d,a,1,b,c| 3
两列由制表符分隔。但是,我希望代码列中的数字位于字母之前,因此输出如下所示:
Code Number
|2,a,c,d,c| 5
|6,b,d,c,b| 2
|1,d,a,b,c| 3
作为一个没有多少 Perl 经验的人,我能想到的最好的方法是根据逗号将文件拆分为数组的散列,然后我可以重新排序列,使包含数字的列排在第一位.理想情况下,无论数字在代码中出现在哪里,我都希望它能正常工作,例如如果 |a,2,c,d,c|
和 |a,c,2,d,c|
以及 |a,c,d,2,c|
也可以实现上述输出。但是,这样做的一个问题是 'code' 列中的不同字母和数字没有不同的标题,我怀疑这可能会在我尝试创建文件的散列时引起一些问题。
到目前为止,我有这段代码:
use strict;
use warnings;
my $file = 'file.txt';
my $output = 'output.txt';
open (my $fh2, '>', $output) or die "Could not open $output $!";
close $fh2;
my %data;
my @datanames;
open ($fh, '<', $file) or die "Could not open $file $!";
open ($fh2, '>>', $output) or die "Could not open $output $!";
while (<$fh>) {
chomp;
my @list=split(/\,/);
for (my $j=0; $j<=$#list; $j++) {
if ($.==1) {
$datanames[$j]=$list[$j];
}
else {
push @{$data{$datanames[$j]}}, $list[$j];
}
}
}
foreach (@datanames){
local $"="\n";
print $fh2 "$_\n@{$data{$_}}\n";
}
close $fh;
close $fh2;
print 'done\n';
如果我有严格和警告,这会给我一大堆未初始化的值错误,即使我不这样做,它也只打印标题(代码和数字),然后对于每一行,|
后跟 code
列中的数值。它看起来像这样:
Code Number
|2
|6
|1
我不确定如何从这一点开始前进,甚至不确定我是否打算以正确的方式解决我的问题。任何帮助将不胜感激。
无需在任何地方存储任何东西。使用 List::MoreUtils::part 根据列是否包含数字对列进行分区。
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
use List::MoreUtils qw{ part };
print scalar <>; # header
while (<>) {
my @cols = split /\t/;
my @subcols = split /[,|]/, $cols[0];
my @parts = part { /[0-9]/ } @subcols[1 .. $#subcols];
print '|', join ',', @{ $parts[1] }, @{ $parts[0] };
print "|\t", $cols[1];
}
我正在尝试使用 Perl 将一些数据重新组织成更有用的格式。当前的数据如下所示:
Code Number
|a,c,2,d,c| 5
|b,d,6,c,b| 2
|d,a,1,b,c| 3
两列由制表符分隔。但是,我希望代码列中的数字位于字母之前,因此输出如下所示:
Code Number
|2,a,c,d,c| 5
|6,b,d,c,b| 2
|1,d,a,b,c| 3
作为一个没有多少 Perl 经验的人,我能想到的最好的方法是根据逗号将文件拆分为数组的散列,然后我可以重新排序列,使包含数字的列排在第一位.理想情况下,无论数字在代码中出现在哪里,我都希望它能正常工作,例如如果 |a,2,c,d,c|
和 |a,c,2,d,c|
以及 |a,c,d,2,c|
也可以实现上述输出。但是,这样做的一个问题是 'code' 列中的不同字母和数字没有不同的标题,我怀疑这可能会在我尝试创建文件的散列时引起一些问题。
到目前为止,我有这段代码:
use strict;
use warnings;
my $file = 'file.txt';
my $output = 'output.txt';
open (my $fh2, '>', $output) or die "Could not open $output $!";
close $fh2;
my %data;
my @datanames;
open ($fh, '<', $file) or die "Could not open $file $!";
open ($fh2, '>>', $output) or die "Could not open $output $!";
while (<$fh>) {
chomp;
my @list=split(/\,/);
for (my $j=0; $j<=$#list; $j++) {
if ($.==1) {
$datanames[$j]=$list[$j];
}
else {
push @{$data{$datanames[$j]}}, $list[$j];
}
}
}
foreach (@datanames){
local $"="\n";
print $fh2 "$_\n@{$data{$_}}\n";
}
close $fh;
close $fh2;
print 'done\n';
如果我有严格和警告,这会给我一大堆未初始化的值错误,即使我不这样做,它也只打印标题(代码和数字),然后对于每一行,|
后跟 code
列中的数值。它看起来像这样:
Code Number
|2
|6
|1
我不确定如何从这一点开始前进,甚至不确定我是否打算以正确的方式解决我的问题。任何帮助将不胜感激。
无需在任何地方存储任何东西。使用 List::MoreUtils::part 根据列是否包含数字对列进行分区。
#! /usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
use List::MoreUtils qw{ part };
print scalar <>; # header
while (<>) {
my @cols = split /\t/;
my @subcols = split /[,|]/, $cols[0];
my @parts = part { /[0-9]/ } @subcols[1 .. $#subcols];
print '|', join ',', @{ $parts[1] }, @{ $parts[0] };
print "|\t", $cols[1];
}