"无法识别的字符\ xEF"无BOM文件出错

时间:2014-06-05 17:37:08

标签: perl csv byte-order-mark

我目前正在使用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在解析和返回值时可能正在创建它。我希望这是对问题的明确解释,如果需要,我可以提供更多细节。提前感谢您给出的任何建议。

1 个答案:

答案 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。这有几个问题:

  1. 您每次都在不必要地设置它
  2. :utf8 binmode没有很好的错误检查,您应该使用:encoding(UTF-8)而不是
  3. 字节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,以获得最佳效果。