【问题标题】:How to remove non-printable character ^@ in perl如何在perl中删除不可打印的字符^@
【发布时间】:2020-10-08 05:06:37
【问题描述】:

我有一个简单的 perl 脚本如下

use strict; 
use warnings 'all';
use Text::CSV;
use open ":std", ":encoding(UTF-8)";
my $in_file = $ARGV[0] or die "Usage: $0 filename\n";
my $out_file = $ARGV[1] or die "Usage: $0 filename\n";
my $csv = Text::CSV->new( { binary => 1, auto_diag => 1 }); 
my $out_csv = Text::CSV->new ( { binary => 1, 
                auto_diag => 1, 
                eol => $/,
                    sep_char => ',', 
                quote_char => '"', 
                always_quote => 1});
open my $data,   '<:encoding(UTF-8)', $in_file or die $!; 
open my $fh_out, '>:encoding(UTF-8)', $out_file or die $!; 

while (my $words = $csv->getline($data))  
{ 
    tr/\r\n//d for @$words;
    tr/,/;/ for @$words;
    tr/"/'/ for @$words;
    $out_csv->print($fh_out, $words);
} 

它所做的只是将 csv 文件转换为更结构化的文件,这种文件很容易被具有限制的外部应用程序理解。该脚本删除不需要的新行、逗号和双引号,它们作为部分用户文本条目输入。这一直运作良好。然而最近在一个输入文件中我们有不可打印的字符 ^@ ,他的脚本没有失败,但输出文件有额外的字符 "0

由于字符不可打印,我不确定我是否可以给出输入文件的示例。请看下面的命令输出。

cat Input.csv 
ObjectId,OrgId,Title,ObjectType,Type,ObjectId,Location,StartDate,EndDate,DueDate,ObjectId1,ObjectId2,ObjectId3,LastModified,IsDeleted,SortOrder,Depth,DummyId,IsHidden,ResultId,DeletedDate,CreatedBy,LastModifiedBy,DeletedBy
3386484,532947,Test,Topic,Auto,3386415,http://www.test.com ,,,,,,,2016-06-27T05:08:26.3070000Z,1,443,3,,False,,2017-02-16T00:31:39.4870000Z,,,

使用 cat -e 选项,您可以看到不可打印的字符。

cat -e Input.csv 
M-oM-;M-?ObjectId,OrgId,Title,ObjectType,Type,ObjectId,Location,StartDate,EndDate,DueDate,ObjectId1,ObjectId2,ObjectId3,LastModified,IsDeleted,SortOrder,Depth,DummyId,IsHidden,ResultId,DeletedDate,CreatedBy,LastModifiedBy,DeletedBy^M$
3386484,532947,Test,Topic,Auto,3386415,http://www.test.com ^@,,,,,,,2016-06-27T05:08:26.3070000Z,1,443,3,,False,,2017-02-16T00:31:39.4870000Z,,,^M$

文件通过脚本后,输出将如下所示。 http://www.test.com 末尾有额外的“0”

cat -e Output.csv 
"M-oM-;M-?ObjectId","OrgId","Title","ObjectType","Type","ObjectId","Location","StartDate","EndDate","DueDate","ObjectId1","ObjectId2","ObjectId3","LastModified","IsDeleted","SortOrder","Depth","DummyId","IsHidden","ResultId","DeletedDate","CreatedBy","LastModifiedBy","DeletedBy"$
"3386484","532947","Test","Topic","Auto","3386415","http://www.test.com "0","","","","","","","2016-06-27T05:08:26.3070000Z","1","443","3","","False","","2017-02-16T00:31:39.4870000Z","","",""$

根据 Dave 的要求添加命令输出

od -ch Input.csv

0000000 357 273 277   O   b   j   e   c   t   I   d   ,   O   r   g   I
           bbef    4fbf    6a62    6365    4974    2c64    724f    4967
0000020   d   ,   T   i   t   l   e   ,   O   b   j   e   c   t   T   y
           2c64    6954    6c74    2c65    624f    656a    7463    7954
0000040   p   e   ,   T   y   p   e   ,   O   b   j   e   c   t   I   d
           6570    542c    7079    2c65    624f    656a    7463    6449
0000060   ,   L   o   c   a   t   i   o   n   ,   S   t   a   r   t   D
           4c2c    636f    7461    6f69    2c6e    7453    7261    4474
0000100   a   t   e   ,   E   n   d   D   a   t   e   ,   D   u   e   D
           7461    2c65    6e45    4464    7461    2c65    7544    4465
0000120   a   t   e   ,   O   b   j   e   c   t   I   d   1   ,   O   b
           7461    2c65    624f    656a    7463    6449    2c31    624f
0000140   j   e   c   t   I   d   2   ,   O   b   j   e   c   t   I   d
           656a    7463    6449    2c32    624f    656a    7463    6449
0000160   3   ,   L   a   s   t   M   o   d   i   f   i   e   d   ,   I
           2c33    614c    7473    6f4d    6964    6966    6465    492c
0000200   s   D   e   l   e   t   e   d   ,   S   o   r   t   O   r   d
           4473    6c65    7465    6465    532c    726f    4f74    6472
0000220   e   r   ,   D   e   p   t   h   ,   D   u   m   m   y   I   d
           7265    442c    7065    6874    442c    6d75    796d    6449
0000240   ,   I   s   H   i   d   d   e   n   ,   R   e   s   u   l   t
           492c    4873    6469    6564    2c6e    6552    7573    746c
0000260   I   d   ,   D   e   l   e   t   e   d   D   a   t   e   ,   C
           6449    442c    6c65    7465    6465    6144    6574    432c
0000300   r   e   a   t   e   d   B   y   ,   L   a   s   t   M   o   d
           6572    7461    6465    7942    4c2c    7361    4d74    646f
0000320   i   f   i   e   d   B   y   ,   D   e   l   e   t   e   d   B
           6669    6569    4264    2c79    6544    656c    6574    4264
0000340   y  \r  \n   3   3   8   6   4   8   4   ,   5   3   2   9   4
           0d79    330a    3833    3436    3438    352c    3233    3439
0000360   7   ,   T   e   s   t   ,   T   o   p   i   c   ,   A   u   t
           2c37    6554    7473    542c    706f    6369    412c    7475
0000400   o   ,   3   3   8   6   4   1   5   ,   h   t   t   p   :   /
           2c6f    3333    3638    3134    2c35    7468    7074    2f3a
0000420   /   w   w   w   .   t   e   s   t   .   c   o   m      \0   ,
           772f    7777    742e    7365    2e74    6f63    206d    2c00
0000440   ,   ,   ,   ,   ,   ,   2   0   1   6   -   0   6   -   2   7
           2c2c    2c2c    2c2c    3032    3631    302d    2d36    3732
0000460   T   0   5   :   0   8   :   2   6   .   3   0   7   0   0   0
           3054    3a35    3830    323a    2e36    3033    3037    3030
0000500   0   Z   ,   1   ,   4   4   3   ,   3   ,   ,   F   a   l   s
           5a30    312c    342c    3334    332c    2c2c    6146    736c
0000520   e   ,   ,   2   0   1   7   -   0   2   -   1   6   T   0   0
           2c65    322c    3130    2d37    3230    312d    5436    3030
0000540   :   3   1   :   3   9   .   4   8   7   0   0   0   0   Z   ,
           333a    3a31    3933    342e    3738    3030    3030    2c5a
0000560   ,   ,  \r  \n
           2c2c    0a0d
0000564

如何在脚本中处理这个问题,我不想在输出 csv 中添加额外的“0”。

谢谢

【问题讨论】:

  • 能否请您补充您的问题,运行od -ch Input.csv 得到的结果。

标签: csv perl character


【解决方案1】:

找到该字符的数值后,您可以使用\x{} 通过该代码编号指定它:

s/\x{....}//g;

例如,如果字符是?,我可以找到它的序数值。我通常使用十六进制转储来做到这一点,但有多种方法。是 U+1F431:

s/\x{1F431}//g;

您还可以为非宽字符指定八进制的代码编号:

s/\200//g;

或者在字符类的范围内使用它们:

s/[\200-\377]//g;
s/[\000-\037]//g;
s/[\000-\037\200-\377]//g;

但是,您可能还想做另一件事。你可以通过它拥有的属性来匹配它(参见perluniprops):

s/\p{XPosixCntrl}//g

或者,用大写的 P,它没有的属性:

s/\P{Print}//g

【讨论】:

  • 谢谢@brian。我会尝试这种方法并让你知道。
【解决方案2】:

所以,我们从文件的十六进制转储中学到了两件事:

  1. 这绝对是一个 UTF8 文件 - 因为前三个字符是 UTF8 字节顺序标记(或 BOM)。
  2. 您的问题字符实际上是一个空字符(代码点为零)。

因此,按照 brian 的建议,您将能够删除该角色:

s/\0//g;

【讨论】:

  • 啊,空字节。您可以安全地从 UTF-8 八位字节中删除这些字符,因为除了 null 之外没有其他字符可以编码为使用 null 字节的序列。
【解决方案3】:

我不确定你是如何发现它是 ^@,但你应该能够通过使用 \c@ 来引用任何这样的东西,其中 \c 代表“CTRL-”。因此,如果它是一个 SOH,\x01,并且您看到它显示为 ^A,您可以指定 s/\cA//g 来删除它

【讨论】:

    猜你喜欢
    • 2020-03-18
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 2017-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多