当字符串包含非拉丁字符时,在tab标签上使用split()函数时出现问题

时间:2013-10-28 19:34:01

标签: regex perl tabs ucs

我正在修改一个Perl脚本,该脚本读取一系列UCS-2LE编码文件,其中的字符串采用制表符分隔格式,但是当字符串包含字符外,我无法在制表符上拆分字符串扩展的拉丁字符集。

以下是我从这些文件(制表符分隔)中读取的示例行:

adını   transcript  asr turkish

当我让我的脚本将这些行写入输出文件以尝试调试此问题时,这就是它的写作:

ad1Ů1ĉtranscript    asr turkish

它似乎无法识别土耳其字符后的制表符。只有当单词以非拉丁字符结尾时才会发生这种情况(因此与选项卡相邻)。

以下是代码块的一部分,其中发生对输出文件的写入并发生字符串拆分:

for my $infile (@ARGV){  
    if (!open (INFILE, "<$infile")){
        die "Couldn't open $infile.\n";
    }    

binmode (OUTFILE, ":utf8");

while (<INFILE>) {
    chomp;
    $tTot++;

    if ($lineNo == 1) {                
        $_ = decode('UCS-2LE', $_);      
    }
    else {
        $_ = decode('UCS-2', $_);
    }    

    $_ =~ s/[\r\n]+//g;    
    my @foo = split('\t');

    my $orth = $foo[0];
    my $tscrpt = $foo[1];
    my $langCode = $foo[3];

    if (exists $codeHash{$langCode}) {
      unless ($tscrpt eq '') {
        check($orth, $tscrpt, $langCode);
      }
    }
    else {
        print OUTFILE "Unknown language code $langCode at line $lineNo.\n";
        print OUTFILE $_; # printing the string that's not being split correctly
        print OUTFILE "\n";
        $tBad++;
    }
  }

此脚本的目的是检查输入文件中的每一行,语言代码是否有效,并根据该代码,根据我们的转录系统检查每个单词的转录是否“合法”

这是我到目前为止所尝试的内容:

  1. 在读入时更改输入字符串的编码 UTF-8,UTF-16或UTF-16LE
  2. 将split()字符更改为'\ w', / [[:blank:]] /,\ p {空白},\ x {09}和\ N {U + 0009}。
  3. 阅读Perl Unicode&amp; perlrebackslash文档和任何其他远程 我在各个网站上找到的相关帖子
  4. 有没有人对我可能会尝试的其他事情有任何建议?提前谢谢!

    我还要提一下,我无法控制输入文件编码和输出文件编码;我必须在UCS-2LE中读取并输出UTF-8。

2 个答案:

答案 0 :(得分:1)

你应该首先使用正确的编码打开文件(不是我知道这是否是正确的,但我正在接受你的话)。然后你不需要调用decode():

open(my $fh, "<:encoding(UCS-2LE)", $file) or die "Error opening $file: $!";
while (<$fh>) {
  ...
}

答案 1 :(得分:0)

感谢大家的评论和一些进一步的研究,我想出了如何解决问题,这与我的想法略有不同;结果是split()问题和编码问题的组合。我必须在显式的open语句中添加编码,而不是在for循环中使用隐式open,并跳过文件开头的前两个字节。

以下是我在问题中发布的部分的修正后的工作代码:

for my $infile (@ARGV){
    my $outfile = $infile . '.out';

    # SOLUTION part 1: added explicit open statement
    open (INFILE, "<:raw:encoding(UCS-2le):crlf", $infile) or die "Error opening $infile: $!";

    # SOLUTION part 2: had to skip the first two bytes of the file 
    seek INFILE, 2, 0;

    if (!open (OUTFILE, ">$outfile")) {
        die "Couldn't write to $outfile.\n";
    }

    binmode (OUTFILE, ":utf8");
    print OUTFILE "Line#\tOriginal_Entry\tLangCode\tOffending_Char(s)\n";

    $tBad = 0;
    $tTot = 0;
    $lineNo = 1;

while (<INFILE>) {
    chomp;
    $tTot++;

    # SOLUTION part 3: deleted the "if" block I had here before that was handling encoding

    # Rest of code in the original block is the same    
}

我的代码现在可以正确识别与不属于扩展拉丁语集的字符相邻的制表符,并按标签分割。

注意:另一个解决方案是将外来词用双引号括起来,但在我们的例子中,我们无法保证我们的输入文件会以这种方式格式化。

感谢所有评论和帮助我的人!