我有一行文件:
$ od -c testData.txt
0000000 6 7 7 7 1 0 \t 0 \t 1 \t L P A Y \t
0000020 F 6 3 5 P 3 B \t L P A Y 0 0 0 0
0000040 1 \t F R M \t H O U S T O N G R
0000060 O U P ( a k a C O R P O R A
0000100 T E A D V O C A T E S I N C
0000120 . ) T H E \t \t \t \t S a c r a m
0000140 e n t o \t C A \t 9 5 8 1 4 - 2 8
0000160 2 5 \t ( 9 1 6 ) 4 4 7 - 9 8 8
0000200 4 \t \t 6 4 9 9 . 9 8 \t 1 7 . 1 9
0000220 \t 0 \t \t 6 5 1 7 . 1 7 \t 3 9 3 0
0000240 9 . 2 3 \t N \t \t \t \r \n
0000253
我有一个完成一件事的脚本:
#!/usr/bin/perl
$line = <STDIN>;
@p = split '\t', $line;
chomp(@p);
for ($idx = 0; $idx < scalar(@p); $idx++) { print $idx.": \"".$p[$idx]."\"\n"; }
exit(0);
我使用的是Mac OS X 10.8.5并使用perl 5(perl 5,版本12,颠覆4(v5.12.4)为darwin-thread-multi-2level构建)。
如果我不通过col传输数据,那么我会看到来自行尾的故障。如果我这样做,则split()函数将忽略几个选项卡。不是全部,只是少数几个。真。烦。
$ ./testSplit < testData.txt
0: "677710"
1: "0"
2: "1"
3: "LPAY"
4: "F635P3B"
5: "LPAY00001"
6: "FRM"
7: "HOUSTON GROUP (aka CORPORATE ADVOCATES INC.) THE"
8: ""
9: ""
10: ""
11: "Sacramento"
12: "CA"
13: "95814-2825"
14: "(916) 447-9884"
15: ""
16: "6499.98"
17: "17.19"
18: "0"
19: ""
20: "6517.17"
21: "39309.23"
22: "N"
23: ""
24: ""
"5: "
$
在上面的最后一行看到轻微的故障。
$ col < testData.txt | ./testSplit
0: "677710"
1: "0"
2: "1"
3: "LPAY"
4: "F635P3B LPAY00001"
5: "FRM"
6: "HOUSTON GROUP (aka CORPORATE ADVOCATES INC.) THE"
7: ""
8: ""
9: ""
10: "Sacramento"
11: "CA"
12: "95814-2825"
13: "(916) 447-9884"
14: ""
15: "6499.98 17.19"
16: "0"
17: ""
18: "6517.17 39309.23"
19: "N"
$
哎呀!
答案 0 :(得分:6)
实际上,col
忽略了标签(它将其中的一些转换为空格):
$ diff -u <(od -c testData.txt) <(col <testData.txt | od -c)
--- /dev/fd/63 2013-11-10 00:06:29.532490383 -0600
+++ /dev/fd/62 2013-11-10 00:06:29.532490383 -0600
@@ -1,12 +1,12 @@
0000000 6 7 7 7 1 0 \t 0 \t 1 \t L P A Y \t
-0000020 F 6 3 5 P 3 B \t L P A Y 0 0 0 0
+0000020 F 6 3 5 P 3 B L P A Y 0 0 0 0
0000040 1 \t F R M \t H O U S T O N G R
0000060 O U P ( a k a C O R P O R A
0000100 T E A D V O C A T E S I N C
0000120 . ) T H E \t \t \t \t S a c r a m
0000140 e n t o \t C A \t 9 5 8 1 4 - 2 8
0000160 2 5 \t ( 9 1 6 ) 4 4 7 - 9 8 8
-0000200 4 \t \t 6 4 9 9 . 9 8 \t 1 7 . 1 9
+0000200 4 \t \t 6 4 9 9 . 9 8 1 7 . 1 9
-0000220 \t 0 \t \t 6 5 1 7 . 1 7 \t 3 9 3 0
+0000220 \t 0 \t \t 6 5 1 7 . 1 7 3 9 3 0
-0000240 9 . 2 3 \t N \t \t \t \r \n
+0000240 9 . 2 3 \t N \n
-0000253
+0000247
要解决实际问题,您需要删除\r
字符。 chomp
不这样做。对于字段25,您基本上正在执行print qq{25: "\r"\n}
。 \r
将光标移回左边距,导致"
覆盖2
。
这是一个清理版本:
#!/usr/bin/perl
use strict;
use warnings;
binmode STDIN, ':crlf';
my $line = <STDIN>;
chomp($line);
my @p = split /\t/, $line, -1;
for my $idx (0 .. $#p) { print $idx.": \"".$p[$idx]."\"\n"; }
exit(0);
主要变化:
binmode STDIN, ':crlf'
在阅读时启用CRLF-&gt; LF翻译。这摆脱了\r
。chomp
只删除了行尾字符,但当你真正想要的是@p
时,扼杀chomp $line
的所有元素是浪费时间。 / LI>
split
。这使空字段保持在最后。否则,输出将以字段22停止。(由于尾随\r
意味着最后一个字段不为空,因此显示空字段。)for
循环更改为使用0 .. $#p
;它更简单。strict
和warnings
始终是个好主意。这需要插入一些my
语句。