Perl 两个csv文件:逐个更改一个csv文件并拉出该行

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

我有两个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  
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的练习;)