我目前正在使用Perl和模块Text::CSV
从CSV文件中提取文本。
每个CSV文件都有引号分隔每个字段。文本将保存到独立的文本文件中,并将选项卡分隔为列。我可以从文本文件中调用并打印每一列没问题,但是当我尝试在循环中使用这些值时,我收到错误Unrecognized character \xEF
。
我的代码示例如下:
#!/usr/bin/perl
use strict;
use warnings;
use Text::CSV;
#### Match ligand data with GPCR interaction data ####
my $csv = Text::CSV->new();
my $file = $ARGV[0];
open (FILE, "<$file");
open (OUT, ">new_$file");
while (my $line2 = <FILE>)
{
binmode(STDOUT, ":utf8");
if ($line2 =~ /^(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)\t(.*?)$/)
{
#### Data from filtered1.txt ####
my $up_fil = $1;
my $ligid_fil = $2;
my $units_fil = $3;
my $low_fil = $4;
my $median_fil = $5;
my $upper_fil = $6;
my $ref = $7;
#### Convert negative log affinity values to normal ####
my $activity = $units_fil;
$activity =~ s/p//;
my $value;
if ($median_fil ne "")
{
$value = $median_fil;
$value = (10**-$median_fil)/(10**-9);
}
elsif ($low_fil ne "" and $upper_fil ne "")
{
my $lower = $low_fil;
$lower = (10**-$low_fil)/(10**-9);
my $upper = $upper_fil;
$upper = (10**-$upper_fil)/(10**-9);
$value = "$upper - $lower";
}
else
{
$value = "n/a";
}
#### Match entries from filtered1.txt with ligands.csv ####
open (LIG, "<ligands.csv");
while (my $line3 = <LIG>)
{
$csv->parse($line3);
my @ligand_fields = $csv->fields();
if (!$ligand_fields[14]) { next; }
if ($ligand_fields[0] eq $ligid_fil)
{
#print OUT "$ligand_fields[14]\t$ligand_fields[13]\t$up_fil\t$ligid_fil\t$activity\t$value\t$ref\n";
print "$ligand_fields[14]\t$ligand_fields[13]\t$up_fil\t$ligid_fil\t$activity\t$value\t$ref\n";
next;
}
}
close LIG;
}
}
close FILE;
close OUT;
我也试过按照以下方式使用正则表达式,但无济于事。
# remove BOM
${$self->{CODE}} =~ s/^(?:
\xef\xbb\xbf |
\xfe\xff |
\xff\xfe |
\x00\x00\xfe\xff |
\xff\xfe\x00\x00
)//x;
原始CSV文件似乎没有任何BOM,因此我怀疑Text::CSV
在解析和返回值时可能正在创建它。我希望这是对问题的明确解释,如果需要,我可以提供更多细节。提前感谢您给出的任何建议。
答案 0 :(得分:2)
Text::CSV
的文档说明你几乎肯定会使用二进制模式。
my $csv = Text::CSV->new ( { binary => 1 } ) # should set binary attribute.
or die "Cannot use CSV: ".Text::CSV->error_diag ();
来自https://metacpan.org/pod/Text::CSV#SYNOPSIS。
您可能还想查看Text::CSV::Encoded
。
我也看到你在STDOUT上设置:utf8
的binmode。这有几个问题:
:utf8
binmode没有很好的错误检查,您应该使用:encoding(UTF-8)
而不是字节0xEF可以出现在UTF-8字节序列中,但仅在非常特定的情况下,它太高(> 0x7F)才能成为单个字符。但是在Perl中\xEF
或\x{ef}
不是指字节0xEF,而是Unicode代码点U + 00EF,它以UTF-8表示为0xC3 0xAF。您可以在Unicode / UTF-8字符表中查看此内容,例如http://www.utf8-chartable.de/。
$ perl -E 'binmode STDOUT, ":encoding(UTF-8)"; say "\xEF";'
ï
所以我认为这就是为什么你的正则表达式删除BOM不起作用。
我建议将three argument open与'<:encoding(UTF-8)'
或'>:encoding(UTF-8)'
一起使用以打开所有输入和输出文件,并在二进制模式下使用Text :: CSV,以获得最佳效果。