好友:
我必须使用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")
不知道为什么。。。我已经尝试使用exec
和eval
,而不是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");
[请注意,我在零之后添加了逗号;当然,在字符串之后也添加了逗号]。
请注意,第一个正则表达式应该可以工作;第二个只是一个"警告",要谨慎。