在perl中进行格式化后,读取一个csv文件并写入另一个csv文件

在perl中进行格式化后,读取一个csv文件并写入另一个csv文件,csv,perl,Csv,Perl,我试图在perl中操作csv 输入csv在列数据中有一些新行字符,这导致其他外部程序失败。我在下面编写了Perl脚本,对csv进行预处理以删除这些字符 use strict; use warnings 'all'; # Using Text::CSV file to allow # full CSV Reader and Writer use Text::CSV; use open ":std", ":encoding(UTF-8)"; my $file = $ARGV[0] or d

我试图在perl中操作csv

输入csv在列数据中有一些新行字符,这导致其他外部程序失败。我在下面编写了Perl脚本,对csv进行预处理以删除这些字符

use strict; 
use warnings 'all';

# Using Text::CSV file to allow 
# full CSV Reader and Writer 
use Text::CSV; 
use open ":std", ":encoding(UTF-8)";
my $file = $ARGV[0] or die; 

my $csv = Text::CSV->new ( 
{ 
    binary => 1, 
    auto_diag => 1, 
    sep_char => ', '
}); 

my $sum = 0; 

# Reading the file 
open(my $data, '<:encoding(utf8)', $file) or die; 

while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words; #removing new lines
    tr/,/;/ for @$words;    #replacing comma with semicolon
    $csv->combine(@$words);
    print $csv->string, "\n";
} 

# Checking for End-of-file 
if (not $csv->eof)  
{ 
    $csv->error_diag(); 
} 
close $data;
我希望可以在perl脚本本身中使用out csv处理程序将输出写入另一个文件。我尝试了两种方法,但总是出现这样或那样的错误。下面是我试过的东西

my $outcsv = Text::CSV->new ( { binary => 1, quote_char => "", escape_char => "\\" } );
open(my $data, '<:encoding(utf8)', $file) or die; 
open(my $fh, ">:encoding(utf8)", "new.csv") or die " new.csv: $!";
while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words;
    tr/,/;/ for @$words;
    $csv->combine(@$words);
    # Open a handle to the file "new.csv"
    $outcsv->print ($fh, $_) for @words;

    #print $csv->string, "\n";
} 

# Checking for End-of-file 
if (not $csv->eof)  
{ 
    $csv->error_diag(); 
} 
close $data;
close $fh or die "new.csv: $!";
这是我在上面发布的第一个代码,但为了编写文件,我使用了shell包装器。现在,我只发布了与第一个不同的第二个perl脚本,当我运行它时,它失败并出现错误。我理解这个错误,但不确定如何修复它。全局符号@words需要在xyz.pl第29行显示包名。由于编译错误,xyz.pl的执行被中止。 如果有人能帮忙,我会非常感激的

谢谢

通过您的操作系统软件包管理器或喜爱的CPAN客户端安装的模块可以轻松转换CSV文件:

#!/usr/bin/env perl
use strict;
use warnings;
use Text::AutoCSV;

Text::AutoCSV->new(in_file => $ARGV[0],
                   out_file => $ARGV[1],
                   encoding => "UTF-8",
                   has_headers => 1, # Set to 0 if no header line
                   read_post_update_hr => \&normalize)->write();

sub normalize {
    my $hr = shift;
    for (values %$hr) {
        s/\r?\n//g;
        tr/,/;/;
    }
}
例如:

$cat input.csv id,消息 1,一个字符串,带逗号 2,另一个 换行 3,废话 $perl demo.pl input.csv new.csv $cat new.csv id,消息 1、一串;用逗号 2,另一个有换行符 3,废话 通过操作系统软件包管理器或喜爱的CPAN客户端安装的模块可轻松转换CSV文件:

#!/usr/bin/env perl
use strict;
use warnings;
use Text::AutoCSV;

Text::AutoCSV->new(in_file => $ARGV[0],
                   out_file => $ARGV[1],
                   encoding => "UTF-8",
                   has_headers => 1, # Set to 0 if no header line
                   read_post_update_hr => \&normalize)->write();

sub normalize {
    my $hr = shift;
    for (values %$hr) {
        s/\r?\n//g;
        tr/,/;/;
    }
}
例如:

$cat input.csv id,消息 1,一个字符串,带逗号 2,另一个 换行 3,废话 $perl demo.pl input.csv new.csv $cat new.csv id,消息 1、一串;用逗号 2,另一个有换行符 3,废话
我不确定你在第一个程序中失败了什么,但这里有点简化和清理

use strict; 
use warnings 'all';

use Text::CSV; 
use open ":std", ":encoding(UTF-8)";

my $file = $ARGV[0] or die "Usage: $0 filename\n";

my $csv = Text::CSV->new({ binary => 1, auto_diag => 1 }); 

open my $data,   '<',        $file or die $!; 
open my $fh_out, '>', 'new_'.$file or die $!; 

while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words;
    tr/,/;/    for @$words;

    $csv->say($fh_out, $words);
} 
我将它们保留为两个循环,以指示单独的处理步骤

上面使用的say in Text::CSV方法是在某个时候添加到模块中的,比该方法旧的版本不会有它。那就可以了

使用print方法,并在构造函数中设置eol以打印换行符

my $csv = Text::CSV->new ( { binary => 1, auto_diag => 1, eol => $/ });
...
$csv->print($fh_out, $words);
还有其他方法可以获得换行符,请参见文档

或者,不要弄乱构造函数,而是手动添加换行符

$csv->print($fh_out, $words);
print $fh_out "\n";
或者,使用迂回的方式

$csv->combine(@$words);
print $fh_out $csv->string, "\n";

请参阅文档

我不确定您在第一个程序中失败了什么,但在这里它有点简化和清理

use strict; 
use warnings 'all';

use Text::CSV; 
use open ":std", ":encoding(UTF-8)";

my $file = $ARGV[0] or die "Usage: $0 filename\n";

my $csv = Text::CSV->new({ binary => 1, auto_diag => 1 }); 

open my $data,   '<',        $file or die $!; 
open my $fh_out, '>', 'new_'.$file or die $!; 

while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words;
    tr/,/;/    for @$words;

    $csv->say($fh_out, $words);
} 
我将它们保留为两个循环,以指示单独的处理步骤

上面使用的say in Text::CSV方法是在某个时候添加到模块中的,比该方法旧的版本不会有它。那就可以了

使用print方法,并在构造函数中设置eol以打印换行符

my $csv = Text::CSV->new ( { binary => 1, auto_diag => 1, eol => $/ });
...
$csv->print($fh_out, $words);
还有其他方法可以获得换行符,请参见文档

或者,不要弄乱构造函数,而是手动添加换行符

$csv->print($fh_out, $words);
print $fh_out "\n";
或者,使用迂回的方式

$csv->combine(@$words);
print $fh_out $csv->string, "\n";

请参阅文档,以下是导致问题的代码:

while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words;
    tr/,/;/ for @$words;
    $csv->combine(@$words);
    # Open a handle to the file "new.csv"
    $outcsv->print ($fh, $_) for @words;

    #print $csv->string, "\n";
}
在评论中,您给了我们一个错误:

全局符号@words需要在d2l_preprocess_csv_files.pl第29行显示包名

我猜第29行是:

$outcsv->print ($fh, $_) for @words;

对getline的调用为您提供了一个数组引用,该数组引用存储在$words中。如果你想把它当作一个数组,你需要去引用它@$words,就像你在一些地方做的那样。因此,在有问题的一行中,您刚刚忘记了美元。您没有名为@words的数组,您需要使用$@words。

以下是导致问题的代码:

while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words;
    tr/,/;/ for @$words;
    $csv->combine(@$words);
    # Open a handle to the file "new.csv"
    $outcsv->print ($fh, $_) for @words;

    #print $csv->string, "\n";
}
在评论中,您给了我们一个错误:

全局符号@words需要在d2l_preprocess_csv_files.pl第29行显示包名

我猜第29行是:

$outcsv->print ($fh, $_) for @words;

对getline的调用为您提供了一个数组引用,该数组引用存储在$words中。如果你想把它当作一个数组,你需要去引用它@$words,就像你在一些地方做的那样。因此,在有问题的一行中,您刚刚忘记了美元。您没有名为@words的数组,您需要使用$@words。

如果您在此处发布示例数据,将不胜感激。另外,请告诉我们failsok是什么以及如何工作的,我发布的第一个代码,但为了编写文件,我使用了shell包装器。现在,我发布的第二个perl脚本的代码与第一个不同,当我运行它时,它失败了,错误如下。我理解错误,但不确定如何修复全局符号@words需要在d2l_preprocess_csv_files.pl第29行显示包名。由于编译错误,d2l_preprocess_csv_files.pl的执行已中止。好的,谢谢你的回复。这类信息需要在问题开始。示例:我马上发现你的第二个程序中有一个@words,我想这是发帖时的一个输入错误,你不小心掉了那美元。但是一旦你显示了错误,我们知道这实际上是个问题。如果你在这里发布示例数据,我们将非常感激。另外,请告诉我们failsok是什么以及如何工作的,我发布的第一个代码,但我使用了shell包装器来编写文件。

现在,我发布的第二个perl脚本的代码与第一个不同,当我运行它时,它失败了,错误如下。我理解错误,但不确定如何修复全局符号@words需要在d2l_preprocess_csv_files.pl第29行显示包名。由于编译错误,d2l_preprocess_csv_files.pl的执行已中止。好的,谢谢你的回复。这类信息需要在问题开始。示例:我马上发现你的第二个程序中有一个@words,我想这是发帖时的一个输入错误,你不小心掉了那美元。但一旦你显示了错误,我们就知道这实际上是个问题。谢谢@zdim!我的第一个程序运行良好,但正如我所说,它不会写入文件,而是写入标准输出。我的第二个程序失败了。我在上面的评论中给出了错误消息。我会测试你的方法,让你知道我的进展。嗨@zdim。当我运行上面的程序时,它会给我一个错误。无法在xyz.pl第18行找到方法say。我的perl版本是Perl5,版本16,Subversion3V5.16.3,是为x86_64-linux-thread构建的-multi@giri啊,这意味着您的Text::CSV比他们介绍的任何时候都要旧,比如说它是在某一点上添加的。然后用他们的指纹instead@giri但是我有相同的Perl,我的Text::CSV版本1.33说…?@giri在回答的末尾添加了选项谢谢@zdim!我的第一个程序运行良好,但正如我所说,它不会写入文件,而是写入标准输出。我的第二个程序失败了。我在上面的评论中给出了错误消息。我会测试你的方法,让你知道我的进展。嗨@zdim。当我运行上面的程序时,它会给我一个错误。无法在xyz.pl第18行找到方法say。我的perl版本是Perl5,版本16,Subversion3V5.16.3,是为x86_64-linux-thread构建的-multi@giri啊,这意味着您的Text::CSV比他们介绍的任何时候都要旧,比如说它是在某一点上添加的。然后用他们的指纹instead@giri但是我有相同的Perl,我的Text::CSV版本1.33说…?@giri在回答的末尾添加了选项谢谢Shawn!我将查看服务器中是否已安装此模块。如果尚未安装,我恐怕无法尝试。谢谢Shawn!我将查看服务器中是否已安装此模块。如果尚未安装,我恐怕无法尝试。嗨,戴夫,谢谢你的回复。尝试了您的建议,但仍然收到一个错误,预期字段在xyz.pl第29行,第1行是数组引用。@giri:我的修复程序将停止您报告的初始错误。如果看不到当前代码的样子,很难提供更多帮助。嗨,Dave,谢谢你的回复。尝试了您的建议,但仍然收到一个错误,预期字段在xyz.pl第29行,第1行是数组引用。@giri:我的修复程序将停止您报告的初始错误。如果看不到当前代码的样子,很难提供更多的帮助。