使用Perl处理CSV输入文件中发现的零时出现问题



好友:

我必须使用Perl语言处理CSV文件,并使用Excel::Writer::XSLX模块生成Excel作为输出。这不是一个家庭作业,而是一个现实生活中的问题,我无法下载任何Perl版本(实际上,我需要使用Perl5.6)或任何Perl模块(我有一组有限的Perl模块)。我的操作系统是UNIX。我还可以使用(在Perl中嵌入)ksh和csh(到目前为止,我已经发现了一些限制)。请把你的答案限制在我现有的工具上。提前感谢!

尽管我不是Perl开发人员,但我来自其他语言,我已经完成了我的工作。然而,客户要求对我陷入困境的地方进行额外处理。

1) 我发现道路上的石头来自两个方面:Perl和Excel处理数据的特殊风格。我已经找到了处理Excel的变通方法,但正如主题中所提到的,我在处理CSV输入文件中的零时遇到了困难。为了处理Excel,我使用'0方式,这是Excel在使用@格式样式时似乎具有的数据表示的最后一种方式。

2) 场景:

我需要捕获可能出现在CSV输入文件的任何行/列/单元格中的独立零,并将它们作为零放在Excel输出文件中。

为了避免浪费你宝贵的时间,我会直接回答我的问题。在我的问题之后,我将提供更多细节:

研究与问题:

  • 我尝试使用Perl正则表达式找到独立的"0",并用任何字符串替换它们,计划在处理结束时将它们替换回"0">
perl -p -i -e 's/b0b/string/g' myfile.csv`

perl -i -ple 's/b0b/string/g'  myfile.csv

正在工作;但只能从命令行执行。当我从Perl脚本调用它们时,它们不起作用,如下所示:

system("perl -i -ple 's/b0b/string/g' myfile.csv")

不知道为什么。。。我已经尝试使用execeval,而不是system,结果相同。

请注意,我有大量的正则表达式可以完美地使用相同的结构,例如:

system("perl -i -ple 's/input/output/g' myfile.csv")

我也尝试过使用backticks和qx//,但没有成功。请注意,qx//和backticks的行为不相同,因为qx//因为正斜杠而抱怨边界\b。

我尝试过使用sed -i,但我的系统拒绝使用-i作为无效标志(不知道是否在所有UNIX中都会发生这种情况,但至少在工作中会发生。但是我接受perl -i)。

我尝试过嵌入awk(它在命令行中工作),通过这种方式:

system `awk -F ',' -v OFS=','  '$1 == "0" { $1 = "string" }1' myfile.csv > myfile_copy.csv

但这只适用于第一列(在命令行中),除了有额外复制文件的缺点外,Perl还抱怨>重定向,认为它"大于"。。。

system(q@awk 'BEGIN{FS=OFS=",";split("1 2 3 4 5",A," ") } { for(i in A)sub(0,"string",$A[i] ) }1' myfile.csv@);

awk在命令行中工作,但只有5列。但在使用@的Perl中没有。

CCD_ 16和CCD_。

我还尝试将每个awk组件作为参数传递给system,用逗号分隔,但没有找到任何有效的方法来传递重定向程序(>),因为Perl因为上述原因拒绝了它。

使用另一种方法,我注意到"独立的零"似乎被Text::CSV模块"吞噬"了,因此,我去掉了它,转而使用传统的逐行循环CSV和逗号分隔符,以这种方式保留零。然而,我在Perl中发现了isdual的"奥秘",并且由于我所拥有的模块的限制,我无法使用Dumper。然后,我还探索了Perl中二进制文件的内核,并尝试了$x ^ $x,它从5.22版本开始就被弃用,但在那个版本之前一直有效(我说我的版本是5.6)。然而,当if( $x ^ $x )为字符串返回TRUE时,if( !( $x ^ $x ) )$x = 0时不返回TRUE。[更新:我在一个专门的Perl脚本中尝试了这个,只是为了这个目的,它正在起作用。我相信我可能的错误结论("不返回TRUE")是在我还没有意识到Text::CSV正在吞噬我的零时得到的。正在做新的测试…]。

我将非常感谢你的帮助

关于我的要求的更多详细信息:

1) 这是一个来自数据库的动态报告,该数据库正在移交给我,我以编程方式从文件夹中获取。动态意味着它可能有任意数量的表,每个表中任意数量的列,作为列标题的名称,每个表的行数。

2) 我不知道,也不可能知道列名,因为它们因报告而异。所以,我不能被列名所引导。

样本输入:

Alfa,Alfa1,Beta,Gamma,Delta,Delta1,Epsilon,Dseta,Heta,Zeta,Iota,Kappa
0,J5,alfa,0,111.33,124.45,0,0,456.85,234.56,798.43,330000.00
M1,0,X888,ZZ,222.44,111.33,12.24,45.67,0,234.56,0,975.33

3) 输入解释

a) 这是一个具有12列和3行的随机报告的示例。第一行是页眉。

b) 我称"独立零"为CSV文件中的"干净"零,从第二行开始,逗号之间,如0,(如果大小写是行中的第一个位置)或后续位置的,0,

c) 在示例的第二行中,您可以从该行的开头读取:0,J5,alfa,0,在这种特殊情况下,它是"单词"或"字符串"。在这种情况下,有4个名称(请注意,其中两个是零,需要将其视为字符串)。因此,我们有一个4名称列的示例(Alfa,Alfa1,Beta,Gamma是这些列的标题,但仅在本场景中)。从那一点开始,在第二行中,您可以看到浮点(*.00)数字,并且在其中,可以看到2个零,它们是数字。最后,在第三行中,您可以读取M1,0,X888,Z,这是前4列的名称。请注意,第二行的第4列的名称为0,而第三行的第四列的名称则为ZZ

摘要:作为一个总体图,我有一个表格报告,从左到右分为两部分:4列为名称,8列为数字。总是前M列是名称,后N列是数字。-不知道哪个数字是M:我将收到用于单词/字符串的列的数量。-不知道哪一个数字是N:我将收到多少列专门用于数字的专栏。-众所周知,在M列数量结束后,总是从N开始,并且这对于所有行都是恒定的。

我已经对正则表达式(b)的Perl边界进行了快速研究,但我还没有发现任何关于它是否适用于Perl5.6的相关信息。

然而,由于您使用的是旧的Perl版本,请尝试传统的UNIX/Linux风格(我的意思是,Perl继承自Shell),如下所示:

system("perl -i -ple 's/^0/string/g' myfile.csv");

如果匹配,上一个regex应该在CSV文件的每一行的开头进行更改。

或者,也许更好(如果你有那些"独立"的零,并且希望避免在一些"前导零"字符串中发生任何不必要的变化):

system("perl -i -ple 's/^0,/string,/g' myfile.csv");

[请注意,我在零之后添加了逗号;当然,在字符串之后也添加了逗号]。

请注意,第一个正则表达式应该可以工作;第二个只是一个"警告",要谨慎。

最新更新