使用Perl或Powershell,如何比较2个CSV文件并仅获取新行?
我正在使用 Perl模块。 Perl程序是从使用Perl或Powershell,如何比较2个CSV文件并仅获取新行?,perl,powershell,csv,compare,diff,Perl,Powershell,Csv,Compare,Diff,我正在使用 Perl模块。 Perl程序是从.bat文件调用的,我将结果放入第三个文件Diff.csv Perl #/usr/bin/env perl 严格使用; 使用警告; 使用Text::Diff; 我的$diff=diff$ARGV[0]=>$ARGV[1]; $diff=~s/^(?:[^\n]*+\n){2}/; $diff=~s/^(?:[\@][^\n]*+)?+\n//mg; 打印$diff; 以下是我如何调用Perl脚本: perl“C:\diffBetweenTwoFile
.bat
文件调用的,我将结果放入第三个文件Diff.csv
Perl
#/usr/bin/env perl
严格使用;
使用警告;
使用Text::Diff;
我的$diff=diff$ARGV[0]=>$ARGV[1];
$diff=~s/^(?:[^\n]*+\n){2}/;
$diff=~s/^(?:[\@][^\n]*+)?+\n//mg;
打印$diff;
以下是我如何调用Perl脚本:
perl“C:\diffBetweenTwoFiles.pl”“C:\File1.csv”“C:\File2.csv”>“C:\Diff.csv”
CSV文件中的一列是Name
目前,结果列出了所有列中的值发生变化的行,但我只想列出新的Name
行
例如:
File1.csv
“姓名”、“出生日期”、“地址”
“一号”、“1/1/01号”、“5号股票道”
“两个”、“1/2/02”、“研究路1号”
文件2.csv
“姓名”、“出生日期”、“地址”
“一号”、“1/1/01号”、“5号股票道”
"二号,"二号,"二号,"二号,"二号,"二号,"二号,"一号,"二号,"研究道111号
“三次”、“2003年1月3日”、“三次加粗”
目前,结果列表如下(包括“两个”,因为其地址已更改):
“姓名”、“出生日期”、“地址”
"二号,"二号,"二号,"二号,"二号,"二号,"二号,"一号
“三次”、“2003年1月3日”、“三次加粗”
但是,我只希望结果列出新的“名称”,如下所示:
“姓名”、“出生日期”、“地址”
“三次”、“2003年1月3日”、“三次加粗”
如何在Perl或Powershell脚本中实现这一点?在Perl中使用
如果在列表上下文中调用子对象,则返回true。因此,调用方通过在列表或标量上下文中调用sub来决定,my($v1,$v2)=f(…)
或my$v=f(…)
,在这种情况下,调用中不需要标志。我选择了更明确的方式
new_names
sub中产生。首先,对“old”arrayref中的所有名称进行查找哈希。然后过滤“new”arrayref中的行,将那些在“old”中没有名称的行(哈希中没有这样的键),并以arrayref[]
的形式返回
这种散列的使用是查找数组之间差异的标准技术用于打印的文档化方法
say
在我的旧版本的模块上不起作用。在这种情况下,请使用打印并在构造函数中进行设置。由于您处理的大文件会增加内存限制,您可以尝试:
每次读取一行第一个CSV文件,并使用哈希表存储文件名条目
一次读取一行第二个CSV文件,并将其名称条目与第一个进行比较
(根据评论更新了)PowerShell中的一个简单示例:
$output = New-Object System.Text.StringBuilder;
$file1 = @{};
$header = $null;
# $filePaths is two-element array with full path to CSV files
for ($i = 0; $i -lt $filePaths.Length; ++$i) {
$reader = New-Object System.IO.StreamReader($filePaths[$i]);
while (($line = $reader.ReadLine()) -ne $null) {
if ($line -match '\S') {
if ($header -eq $null) {
$header = $line;
$output.AppendLine($line) | Out-Null;
}
$name = ($line -split ',')[0];
switch ($i) {
0 { $file1.Add($name, $null); }
1 {
if (!$file1.ContainsKey($name)) {
$output.AppendLine($line) | Out-Null;
}
}
}
}
}
$reader.Dispose();
}
$output.ToString() | Out-File -FilePath $outPath;
在Powershell中,您需要使用导入csv
导入csv。然后可以使用比较对象
进行比较。您可以从那里导出CSV
(或任何您想要的格式)。如果要筛选出所需的匹配项,可以使用| Where Object
。这应该给你一个好的起点。一旦您尝试了自己的解决方案,并且无法使用更新的脚本更新OP。那么我们可以帮你。谢谢你的回复。我以前尝试过使用Compare对象,但由于文件太大,它耗尽了我机器上的所有RAM,从未完成。是否有其他方法可以做到这一点,例如使用Perl?上面的Perl脚本可以工作,除了我只需要新的“Name”行。如果您使用Perl创建输出,我认为使用Perl将是最好的选择。建立所需输出的某种条件可能就是您所寻找的。不幸的是,我对Perl不够精通,无法为您提供使用Perl的解决方案的最佳路径。以下是适合您的用例的解决方案。这些“大文件”到底有多大?它们分类了吗?我认为很明显,比较CSV文件的各个字段超出了Text::Diff
,您需要编写一些特定的代码。谢谢zdim。它给了我错误“在@INC.中找不到类/CSV.pm”。我在3个不同的位置找到了CSV.pm:C:\Perl64\lib\SQL\dialogs\CSV.pm、C:\Perl64\lib\DBD\CSV.pm和C:\Perl64\lib\Bundle\DBD\CSV.pm。我在程序本身中使用lib命令添加搜索路径,如下所示,但仍然得到相同的错误:#/usr/bin/env perl使用lib'C:\Perl64\lib\Bundle\DBD';使用Class::CSV;使用Text::CSV;另外,在您的代码中,我是否将File1 File2 Diff替换为c:\File1.txt c:\File2.txt和c:\Diff.csv?前两个文件实际上是一个TXT文件,但逗号分隔,就像CSV文件一样。@faujong-ugh,模块的安装有些混乱。(这是值得澄清的,因为这只是CSV的一个转到模块。)至于文件名,您可以每行列出一个,因为您的第三个文件具有不同的扩展名,这可能更简单。您知道我如何修复“在@INC中找不到class/CSV.pm”错误吗?对于文件名,您是想这样列出它们吗?my$file_old=“c:\File1.txt”;my$file_new=“c:\File2.txt”;我的$file_diff=“c:\diff.csv”;(要替换这一行my($file\u old,$file\u new,$file\u diff)=map{$\u.'.csv'}qw(File1 File2 diff))?@faujong我不知道Windows安装是如何工作的,但在我的(Linux)系统上,csv.pm
位于Text/
目录中。也许您根本没有Text::CSV
模块,而您的系统正在接收一些其他相关的模块?(还有,class/csv.pm
令人担忧……它会引用“class::csv”模块?输入错误?)。我将针对此错误创建一个关于StackOverflow的不同问题。至于文件名,我理解对了吗?@kujibo谢谢。我将Write Host$line.Trim()替换为这样的文件:$writer=newobjectsystem.IO.StreamWriter(“c:\Diff.csv”);而(($line=$reader.ReadLine())-ne$null)
return wantarray ? ( LIST ) : scalar;
$output = New-Object System.Text.StringBuilder;
$file1 = @{};
$header = $null;
# $filePaths is two-element array with full path to CSV files
for ($i = 0; $i -lt $filePaths.Length; ++$i) {
$reader = New-Object System.IO.StreamReader($filePaths[$i]);
while (($line = $reader.ReadLine()) -ne $null) {
if ($line -match '\S') {
if ($header -eq $null) {
$header = $line;
$output.AppendLine($line) | Out-Null;
}
$name = ($line -split ',')[0];
switch ($i) {
0 { $file1.Add($name, $null); }
1 {
if (!$file1.ContainsKey($name)) {
$output.AppendLine($line) | Out-Null;
}
}
}
}
}
$reader.Dispose();
}
$output.ToString() | Out-File -FilePath $outPath;