我需要处理许多文件(以CRLF
行结尾),它们看起来像这样:
$ cat -v file1.txt
1$XXX$ZZZ$$$$$$$$^M
2$AAA$BBB$$$$$$$$^M
$ cat -v file2.txt
1$4668$$$^M
2$46$$$^M
我需要:
- 删除最后一个
$
符号, - 将所有
$
更改为,
, - 用双引号将每个字段括起来,
- 重命名文件。
所需输出(无论行尾是CRLF
还是LF
):
$ cat newname1.csv
"1","XXX","ZZZ","","","","","","",""
"2","AAA","BBB","","","","","","",""
$ cat newname2.csv
"1","4668","",""
"2","46","",""
以下是我的尝试:
#!/usr/bin/perl
use strict;
use warnings;
my %inputs = qw(
file1 file1.txt
file2 file2.txt
);
my %outputs = qw(
file1 newname1.csv
file2 newname2.csv
);
for my $key (keys %inputs) {
open my $in, '<', $inputs{$key} or die $!;
open my $out, '>', $outputs{$key} or die $!;
while(<$in>) {
local $, = ',';
local $\ = "\n";
s/\$$//;
my @row = split /\$/;
print $out map qq("$_"), @row;
}
close $in or die $!;
close $out or die $!;
}
在Linux上,它给出了最后一列包含CRLF
的文件和LF
行结尾:
$ cat -v newname1.csv
"1","XXX","ZZZ","","","","","","","","^M
"
"2","AAA","BBB","","","","","","","","^M
"
$ cat -v newname2.csv
"1","4668","","","^M
"
"2","46","","","^M
"
我猜这个问题是由于CRLF
行结束。因此,我尝试:
- 将
'<'
更改为'<:crlf'
以打开我的文件,结果相同; - 使用其他正则表达式来匹配最后一个
$
符号(例如\$\r\n
和\$\R
,这两个文件都没有空的尾部列)。
我如何修复我的代码以获得我想要的输出?
2条答案
按热度按时间ki1q1bka1#
更新:这个答案是为前两个版本的问题写的。我只是因为OP要求我取消删除它。它可能不适合当前版本的问题。有些事情可能是完全错误的。
这与行尾是否为CRLF无关。这只是一个
split
的问题。如果我在代码中添加一个Dumper打印,其中您已拆分为变量
@row
我得到(对于第一个字段):
在分割的最后一个字段中可以看到尾随的换行符。
然后,当您将这些拆分结果视为数据中的真正列值时,将为换行符添加1个字段。
我看不出你在哪里删除最后一个
$
。也许这是你误解了什么?建议方案:
如果这是csv数据,您应该使用csv模块来处理它。
Text::CSV
模块很好地做到了这一点。下面是一个处理输入的示例代码:更新:
自从你编辑了你的问题并添加了一行代码,改变了 * 一切 * 并使你自己声称的输出“错误”,我发现了以下内容:
如果只有尾随的空字段,默认情况下
split
将删除这些空字段。这是可以修复的,如documentation for split:如果LIMIT是负的,则它被视为任意大的;产生尽可能多的场。
如果LIMIT被省略(或者,等价地,零),则它通常被视为好像它是负的,但是例外的是尾部空字段被剥离(空的前导字段总是被保留);如果所有字段都是空的,则所有字段都被认为是拖尾的(并且因此在这种情况下被剥离)。
换句话说,你可以改变
到
以修复丢失的尾随空字段。
唯一的问题是你还没有报告有这个问题(还没有)。所以,我想我们需要等待你更新你的问题。
brjng4g32#
Text::CSV
模块,但破译这个问题是有教育意义的。代码中有两个问题:
1.当使用
\$\r\n
或\$\R
来匹配最后一个$
符号时,它按预期工作。然而,由于最后一列是空的(即,没有CRLF
包含在最后一列中),split
drop them by default。1.当使用
\$$
来匹配最后一个$
符号时,CRLF
被包含在最后一列中(我不明白为什么);在Linux上,一个可能的修复方法是:
split /\$/;
更改为split /\$/, $_, -1;
来指定split
的LIMIT
参数(以修复问题1);$
符号,从\$$
更改为\$\r\n
(或\$\R
);(以下简称myscript_fix1.pl
)while
循环的开始添加local $/ = "\r\n"; chomp;
,并保持正则表达式\$$
与最后一个$
匹配;(以下简称myscript_fix2.pl
)$
符号(即,删除s/\$$//;
),并在split
之后添加pop @row;
。(以下简称myscript_fix3.pl
)在Windows上,需要进行一些调整。
在我的机器上使用
file1.txt
和file2.txt
的一些计时重复了10000次: