Проблема в Perl с использованием функции split() на символах табуляции, когда строка содержит не латинские символы

Я работаю над модификацией сценария 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{Blank}, \x{09} и \N{U+0009}.
  3. Чтение документации по Perl Unicode и perlrebackslash, а также любых других сообщений, имеющих отношение к удаленному сайту, которые я смог найти на различных сайтах

У кого-нибудь есть какие-либо предложения относительно других вещей, которые я мог бы попробовать? Заранее спасибо!

Я должен также упомянуть, что я не контролирую ни кодировку входного файла, ни кодировку выходного файла; Я должен читать в UCS-2LE и выводить UTF-8.

2 ответа

Решение

Благодаря всем комментариям и дальнейшим исследованиям я выяснил, как решить проблему, и она немного отличалась от моей; Оказалось, что это была комбинация проблемы split() и проблемы с кодировкой. Мне пришлось как добавить кодировку в явном операторе открытия вместо использования неявного открытия в цикле for, так и пропустить первые два байта в начале файла.

Вот как выглядит исправленный рабочий код для раздела, который я разместил в своем вопросе:

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    
}

Мой код теперь правильно распознает символы табуляции рядом с символами, не входящими в расширенный латинский набор, и разбивается на вкладки, как и должно быть.

ПРИМЕЧАНИЕ. Другим решением было бы заключить иностранные слова в двойные кавычки, но в нашем случае мы не могли гарантировать, что наши входные файлы будут отформатированы таким образом.

Спасибо всем, кто прокомментировал и помог мне!

Вы должны начать с открытия файла с правильной кодировкой (не то, чтобы я знал, правильная ли это или нет, но я беру ваше слово за это). Тогда вам не нужно вызывать decode():

open(my $fh, "<:encoding(UCS-2LE)", $file) or die "Error opening $file: $!";
while (<$fh>) {
  ...
}
Другие вопросы по тегам