我正在开发一个程序,该程序将CSV文件中的信息作为源来搜索,并通过具有“客户包”的文本文件进行搜索。我只对一些条目感到奇怪,我似乎无法弄清楚导致重复计数的原因。任何人都可以查看我的代码并告诉我我的逻辑/语法是否关闭? (可能是)。我想要完成的是计算csv文件(packageid,package_description)中条目的文本文件中的总出现次数
感谢您的帮助!我在这里疯狂。
#!/usr/bin/perl
use strict;
use Text::CSV;
# Variables already declared in the other PL file ** Remove if consolidating **
my $file2 = 'master_plist.csv';
my $csv2 = Text::CSV->new(); # Create a Text::CSV object
open (CSV2, "<", $file2) or die $!; #open CSV file for parsing
while (<CSV2>) {
if ($csv2->parse($_)) {
my @columns2 = $csv2->fields(); # Parse CSV and load into an array for each row.
my $packID = $columns2[0];
my $packDESC = $columns2[1];
my $val = 'customer_packages_report.txt';
chomp ($val);
my $cnt=0;
open (HNDL, "$val") || die "wrong filename";
while ($val = <HNDL>)
{
while ($val =~ /$packID - $packDESC/ig)
{
$cnt++;
}
}
#if ($packDESC =~ /\(/g) {
# $packDESC =~ s/\(/\(/g;
#}
print "Total iterations of $packDESC: $cnt\n";
close (HNDL);
# End original code
} # Close IF
} # Close WHILE
close CSV;
答案 0 :(得分:2)
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
# Variables already declared in the other PL file ** Remove if consolidating **
my $file2 = 'master_plist.csv';
my $csv2 = Text::CSV->new(); # Create a Text::CSV object
open (CSV2, "<", $file2) or die "I die while opening $file2! $!"; #open CSV file for parsing
while ($each_csv2_line=<CSV2>) {
if ($csv2->parse($each_csv2_line)) {
my @columns2 = $csv2->fields(); # Parse CSV and load into an array for each row.
my $packID = $columns2[0];
my $packDESC = $columns2[1];
my $val = 'customer_packages_report.txt';
chomp ($val);
my $cnt=0;
open (HNDL,"<","$val") or die "wrong filename: $val! $!";
while (<HNDL>){
$cnt++ while (/$packID - $packDESC/ig);
}
#if ($packDESC =~ /\(/g) {
# $packDESC =~ s/\(/\(/g;
#}
print "Total iterations of $packDESC: $cnt\n";
close (HNDL);
# End original code
} # Close IF
} # Close WHILE
# end of script
close CSV;
我的建议:
$HNDL instead of HNDL
&lt; - 文件句柄的词法变量。defined
和==0
和eq ""
)writeonly
代码。示例(以及引用):
“线路输入操作员<>
的情况完全相同,尽管Perl会自动为您执行此操作。
看起来你正在测试STDIN中的这一行:
while (<STDIN>) {
do_something($_);
}
但是,这是一个特殊情况,Perl会自动转换为检查$_
的定义:
while ( defined( $_ = <STDIN> ) ) { # implicitly done
do_something($_);
}
” 有效的Perl编程,第24页。
答案 1 :(得分:2)
您可以做很多事情来改进代码:
use warnings;
。$file2
(没有意义,为什么没有文件1?),请使用$package_file
或任何有意义的内容。Text::CSV
,则可以使用$csv->getline()
逐行浏览文件。这将简化您的代码。 See the documentation for an example。chomp($val)
从字符串末尾删除换行符。您在刚刚声明的字符串文字中使用它,它没有换行符。这没有意义。$val
)来完成两件完全不同的事情。这非常令人困惑。您在正则表达式中插入的变量可能包含特殊字符吗?如果是这样,你需要逃脱它们。例如,如果$packDESC
包含句点,则它将匹配正则表达式中的任何字符。要按字面意思处理变量的内容,请使用\Q..\E
,如下例所示:/\Q$packID - $packDESC\E/ig
。
您正在打开customer_packages_report.txt并在csv文件的每一行上逐行浏览。你可以通过在中读取并将结果存储在一个数组中来简化它。
$cnt = () = /$packID - $packDESC/ig;
。这将匹配放在数组上下文中,返回一个匹配数组,然后将其放回标量上下文中以计算匹配。有点棘手,但更简单。如果没有看到数据,很难确切地说出导致问题的原因。您是否有一些不必要的重复,这些重复源于您对两个文件的嵌套循环?我将从重写改进代码开始,然后查看问题是否仍然存在。
答案 2 :(得分:1)
您的代码似乎使用perl -c
编译而没有错误,所以这很好。如果我猜,我会认为你的问题在于你的某些领域有元字符。正则表达式/$packID - $packDESC/
容易受到元字符的影响。例如
my $str = "foo? bar";
$str =~ /$str/; # returns false, because ? is a meta character
在上面的示例中,问号?
是一个量词,它影响到它之前的任何内容,因此o?
表示“0或1 o”。要解决元字符问题,请使用\Q ... \E
转义符:
$str =~ /\Q$str/; # will now match
使用\E
终止转义序列是可选的。
其他一些注意事项:
use strict
非常好。您还应始终use warnings
。不这样做不是删除代码中的问题,只是隐藏它们。Text::CSV
对象。根据您的输入,可能适合也可能不适合。在the documentation。binary => 1
parse()
函数可能不是最佳选择,文档对getline
有好话要说。$val
来读取您的文件。虽然从技术上说应该工作,但它却在寻找麻烦。风格和练习笔记及实用技巧:
my @columns2 = $csv2->fields();
my $packID = $columns2[0];
my $packDESC = $columns2[1];
可以这样写
my ($packID, $packDESC) = $csv2->fields();
$val
。这是多余的,因为chomp
默认情况下仅从字符串末尾删除换行符,并且您没有添加任何此类换行符。它不会改变任何东西,但这里不需要。如果您从stdin或文件中读取内容,则可能需要使用chomp
。die
而不提及错误$!
是让自己烦恼的可靠方法。答案 3 :(得分:1)
由于很多人已经对您的程序本身进行过评论,我将谈谈如何成为一名更好的Perl程序员,并帮助以有助于消除您的许多问题的方式编写。
查看Perl::Tidy并完成您的程序。这将有助于改善您的语法和Perl,并将帮助您解决许多您遇到的各种问题。
另外,你应该得到Perl Best Practices的副本,这是Perl Tidy的大部分内容。并且,正如已经引用Effective Perl Programming的人是另一本优秀的书。
Perl的一大问题是很少有人学习它。大多数人都陷入了我们不得不自己捡起来的情况。另外,Perl是一种相当陈旧且相当苛刻的语言。大多数Perl书籍仍然严重依赖于Perl 3.x编程方式,并且没有提到使用use strict;
和use warnings;
这样的基础知识。
你结合了旧的编程实践,大多数人通过使用旧语法破解老式程序来学习Perl(可能是通过黑客攻击甚至更旧的程序来学习Perl的人),你可以看到为什么Perl有作为只写语言的声誉。
答案 4 :(得分:0)
您可能希望使用getline
中的Text::CSV
方法,该方法可以保存几行代码。
问题可能是因为您在搜索的字符串中有正则表达式元字符。在正则表达式中使用\Q...\E
转义它们,以便按字面意思取消它们。在下面的重写中,我还添加了\s*
而不是文字空格,以防连字符两边没有一个空格。
我还将文件句柄更改为词法句柄,这样做的好处是当句柄超出范围时它们会自动关闭。
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
my $file2 = 'master_plist.csv';
my $csv2 = Text::CSV->new();
open(my $csv_fh, '<', $file2) or die $!;
while (my $row = $csv2->getline($csv_fh)) {
my ($packID, $packDESC) = @$row;
my $val = 'customer_packages_report.txt';
chomp($val);
open(my $fh, '<', $val) or die "wrong filename";
my $cnt = 0;
while ($val = <$fh>) {
while ($val =~ /\Q$packID\E\s*-\s*\Q$packDESC\E/ig) {
$cnt++;
}
}
print "Total iterations of $packDESC: $cnt\n";
}