Perl 两个csv文件:逐个更改一个csv文件并拉出该行
我有两个CSV文件。第一个是列表文件,它包含ID和名称。比如说Perl 两个csv文件:逐个更改一个csv文件并拉出该行,perl,csv,awk,grep,Perl,Csv,Awk,Grep,我有两个CSV文件。第一个是列表文件,它包含ID和名称。比如说 1127100,Acanthocolla cruciata 1127103,Acanthocyrta haeckeli 1127108,Acanthometra fusca 第二个是我想要交换的内容,如果找到匹配项,我将通过第一个数字提取该行。第一列数字对应于每个文件。比如说 1127108,1,0.60042 1127103,1,0.819671 1127100,2,0.50421,0.527007 102
1127100,Acanthocolla cruciata
1127103,Acanthocyrta haeckeli
1127108,Acanthometra fusca
第二个是我想要交换的内容,如果找到匹配项,我将通过第一个数字提取该行。第一列数字对应于每个文件。比如说
1127108,1,0.60042
1127103,1,0.819671
1127100,2,0.50421,0.527007
10207,3,0.530422,0.624466
所以我想以这样的CSV文件结束
Acanthometra fusca,1,0.60042
Acanthocyrta haeckeli,1,0.819671
Acanthocolla cruciata,2,0.50421,0.527007
use strict;
use warnings;
open my $csv_score, '<', "$ARGV[0]" or die qq{Failed to open "$ARGV[0]" for input: $!\n};
open my $csv_list, '<', "$ARGV[1]" or die qq{Failed to open "$ARGV[1]" for input: $!\n};
open my $out, ">$ARGV[0]_final.txt" or die qq{Failed to open for output: $!\n};
my $string = do {
local $/;
<$csv_score>;
};
while ( <$csv_list> ) {
chomp;
my ( $find, $replace ) = split /,/;
$string =~ s/$find/$replace/g;
}
print $out $string;
close $csv_score;
close $csv_list;
close $out;
我尝试了Perl,但同时打开两个文件却很混乱。所以我尝试将其中一个CSV文件转换为字符串,并以这种方式对其进行解析,但没有成功。但是后来我读到了关于grep
和其他一行程序的文章,但我对它并不熟悉。格雷普能做到这一点吗
这是我试过的Perl代码
use strict;
use warnings;
open my $csv_score, '<', "$ARGV[0]" or die qq{Failed to open "$ARGV[0]" for input: $!\n};
open my $csv_list, '<', "$ARGV[1]" or die qq{Failed to open "$ARGV[1]" for input: $!\n};
open my $out, ">$ARGV[0]_final.txt" or die qq{Failed to open for output: $!\n};
my $string = <$csv_score>;
while ( <$csv_list> ) {
my ($find, $replace) = split /,/;
$string =~ s/$find/$replace/g;
if ($string =~ m/^$replace/){
print $out $string;
}
}
close $csv_score;
close $csv_list;
close $out;
使用严格;
使用警告;
打开我的$csv_分数,您的代码失败,因为您只读取了$csv_分数
文件的第一行,并且每次更改时都试图打印$string
。您也未能从$csv\u列表
文件的行末尾删除换行符。如果你解决了这些问题,那么它看起来是这样的
Acanthometra fusca,1,0.60042
Acanthocyrta haeckeli,1,0.819671
Acanthocolla cruciata,2,0.50421,0.527007
use strict;
use warnings;
open my $csv_score, '<', "$ARGV[0]" or die qq{Failed to open "$ARGV[0]" for input: $!\n};
open my $csv_list, '<', "$ARGV[1]" or die qq{Failed to open "$ARGV[1]" for input: $!\n};
open my $out, ">$ARGV[0]_final.txt" or die qq{Failed to open for output: $!\n};
my $string = do {
local $/;
<$csv_score>;
};
while ( <$csv_list> ) {
chomp;
my ( $find, $replace ) = split /,/;
$string =~ s/$find/$replace/g;
}
print $out $string;
close $csv_score;
close $csv_list;
close $out;
然而,这不是一种安全的方法,因为ID可能会在其他地方找到,而不是在一行的开头
我会像这样从$csv\u列表
文件中构建一个散列,这也使程序更加简洁
use strict;
use warnings;
use v5.10.1;
use autodie;
my %ids;
{
open my $fh, '<', $ARGV[1];
while ( <$fh> ) {
chomp;
my ($id, $name) = split /,/;
$ids{$id} = $name;
}
}
open my $in_fh, '<', $ARGV[0];
open my $out_fh, '>', "$ARGV[0]_final.txt";
while ( <$in_fh> ) {
s{^(\d+)}{$ids{$1} // $1}e;
print $out_fh $_;
}
使用严格;
使用警告;
使用v5.10.1;
使用自动模具;
我的%id;
{
打开我的$fh,你的代码失败了,因为你只读取了$csv\u分数
文件中的第一行,每次更改时你都试图打印$string
。你也未能从$csv\u列表
文件的行尾删除换行符。如果你修复了这些问题,那么看起来是这样的
Acanthometra fusca,1,0.60042
Acanthocyrta haeckeli,1,0.819671
Acanthocolla cruciata,2,0.50421,0.527007
use strict;
use warnings;
open my $csv_score, '<', "$ARGV[0]" or die qq{Failed to open "$ARGV[0]" for input: $!\n};
open my $csv_list, '<', "$ARGV[1]" or die qq{Failed to open "$ARGV[1]" for input: $!\n};
open my $out, ">$ARGV[0]_final.txt" or die qq{Failed to open for output: $!\n};
my $string = do {
local $/;
<$csv_score>;
};
while ( <$csv_list> ) {
chomp;
my ( $find, $replace ) = split /,/;
$string =~ s/$find/$replace/g;
}
print $out $string;
close $csv_score;
close $csv_list;
close $out;
然而,这不是一种安全的方法,因为ID可能会在其他地方找到,而不是在一行的开头
我会像这样从$csv\u列表
文件中构建一个散列,这也使程序更加简洁
use strict;
use warnings;
use v5.10.1;
use autodie;
my %ids;
{
open my $fh, '<', $ARGV[1];
while ( <$fh> ) {
chomp;
my ($id, $name) = split /,/;
$ids{$id} = $name;
}
}
open my $in_fh, '<', $ARGV[0];
open my $out_fh, '>', "$ARGV[0]_final.txt";
while ( <$in_fh> ) {
s{^(\d+)}{$ids{$1} // $1}e;
print $out_fh $_;
}
使用严格;
使用警告;
使用v5.10.1;
使用自动模具;
我的%id;
{
打开my$fh,“编写的代码的问题是您只执行一次:
my $string = <$csv_score>;
注意-这仍然会打印源内容的最后一行:
"Acanthometra fusca ",1,"0.60042 "
"Acanthocyrta haeckeli ",1,"0.819671 "
"Acanthocolla cruciata ",2,0.50421,"0.527007 "
(您的数据包含空格,因此Text::CSV
将其用引号括起来)
如果要放弃该选项,则可以测试是否确实发生了替换:
if ( $row->[0] =~ s/^($search)$/$replace{$1}/ ) {
$csv->print( \*STDOUT, $row );
print "\n";
}
(当然,如果你确信你不会有任何CSV
通常支持的古怪的东西,你可以继续使用split/,/
。编写的代码的问题是,你只做一次:
my $string = <$csv_score>;
注意-这仍然会打印源内容的最后一行:
"Acanthometra fusca ",1,"0.60042 "
"Acanthocyrta haeckeli ",1,"0.819671 "
"Acanthocolla cruciata ",2,0.50421,"0.527007 "
(您的数据包含空格,因此Text::CSV
将其用引号括起来)
如果要放弃该选项,则可以测试是否确实发生了替换:
if ( $row->[0] =~ s/^($search)$/$replace{$1}/ ) {
$csv->print( \*STDOUT, $row );
print "\n";
}
(当然,如果你确信你不会有任何正常支持的CSV
古怪的东西,你可以继续使用split/,/
。我想提供一种非常不同的方法
假设您使用数据库比使用Perl的数据结构更为方便。您可以使用将您的CSV文件转换为某种关系数据库。它在引擎盖下使用Text::CSV(帽子尖到@Sobrique)。您需要从CPAN安装它,因为它没有捆绑在默认发行版中
use strict;
use warnings;
use Data::Printer; # for p
use DBI;
my $dbh = DBI->connect( "dbi:CSV:", undef, undef, { f_ext => '.csv' } );
$dbh->{csv_tables}->{names} = { col_names => [qw/id name/] };
$dbh->{csv_tables}->{numbers} = { col_names => [qw/id int float/] };
my $sth_select = $dbh->prepare(<<'SQL');
SELECT names.name, numbers.int, numbers.float
FROM names
JOIN numbers ON names.id = numbers.id
SQL
# column types will be silently discarded
$dbh->do('CREATE TABLE result ( name CHAR(255), int INTEGER, float INTEGER )');
my $sth_insert =
$dbh->prepare('INSERT INTO result ( name, int, float ) VALUES ( ?, ?, ? ) ');
$sth_select->execute;
while (my @res = $sth_select->fetchrow_array ) {
p @res;
$sth_insert->execute(@res);
}
生成的文件如下所示:
$ cat scratch/result.csv
name,int,float
"Acanthocolla cruciata",2,0.50421
"Acanthocyrta haeckeli",1,0.819671
"Acanthometra fusca",1,0.60042
我想提供一种非常不同的方法
假设您使用数据库比使用Perl的数据结构更为方便。您可以使用将您的CSV文件转换为某种关系数据库。它在引擎盖下使用Text::CSV(帽子尖到@Sobrique)。您需要从CPAN安装它,因为它没有捆绑在默认发行版中
use strict;
use warnings;
use Data::Printer; # for p
use DBI;
my $dbh = DBI->connect( "dbi:CSV:", undef, undef, { f_ext => '.csv' } );
$dbh->{csv_tables}->{names} = { col_names => [qw/id name/] };
$dbh->{csv_tables}->{numbers} = { col_names => [qw/id int float/] };
my $sth_select = $dbh->prepare(<<'SQL');
SELECT names.name, numbers.int, numbers.float
FROM names
JOIN numbers ON names.id = numbers.id
SQL
# column types will be silently discarded
$dbh->do('CREATE TABLE result ( name CHAR(255), int INTEGER, float INTEGER )');
my $sth_insert =
$dbh->prepare('INSERT INTO result ( name, int, float ) VALUES ( ?, ?, ? ) ');
$sth_select->execute;
while (my @res = $sth_select->fetchrow_array ) {
p @res;
$sth_insert->execute(@res);
}
生成的文件如下所示:
$ cat scratch/result.csv
name,int,float
"Acanthocolla cruciata",2,0.50421
"Acanthocyrta haeckeli",1,0.819671
"Acanthometra fusca",1,0.60042
所有UNIX安装附带的通用文本处理工具名为awk
:
$ awk -F, -v OFS=, 'NR==FNR{m[$1]=$2;next} $1=m[$1]' file1 file2
Acanthometra fusca,1,0.60042
Acanthocyrta haeckeli,1,0.819671
Acanthocolla cruciata,2,0.50421,0.527007
所有UNIX安装附带的通用文本处理工具名为awk
:
$ awk -F, -v OFS=, 'NR==FNR{m[$1]=$2;next} $1=m[$1]' file1 file2
Acanthometra fusca,1,0.60042
Acanthocyrta haeckeli,1,0.819671
Acanthocolla cruciata,2,0.50421,0.527007
请显示您遇到问题的代码。如我所怀疑的,如果没有问题,那么您应该离开并编写一些代码,因为堆栈溢出是一种认知基础,而不是完成工作的自由方式。我们将帮助您解决代码中的特定问题,但我们通常不会为您的问题实现解决方案specification@Borodin编辑战争!:D乍一看,这实际上是非常清晰的Perl代码。你自己写的吗?我包括了我刚才提到的Perl代码。这些文件有多大?请显示你有问题的代码。如果没有,正如我所怀疑的,那么你应该离开去写一些,因为堆栈溢出是一种认知基础,而不是一种免费的获取方法完成您的工作。我们将帮助您解决代码中的特定问题,但我们通常不会为您的代码实现解决方案specification@Borodineditwar!:第一眼看上去,这实际上是非常清晰的Perl代码。你自己写的吗?我包括了我刚才提到的Perl代码。这些文件有多大?快告诉我!我会有一个dded警告可能出现在一个文件中,而另一个文件中没有ID,但可能没有必要,或者是OP的练习;)请告诉我!如果ID出现在一个文件中,而另一个文件中没有ID,但可能没有必要,我可能会添加警告,或者是OP的练习;)