LINUX.ORG.RU

UTF-8 и борьба с ним

 ,


0

1

Приветствую!

Есть задача распарсить некий csv-файл и поля сложить в базу.

Вся беда в том, что значения неких полей написаны в смешанной кодировке. К примеру, название выглядит вот так: ΝΙΚΟLΟPΟΥLΟS Ν. ΙΟAΝΝIS Но большинство букв там не латинские. Вот как эта надпись выглядит в дампе:

$VAR1 = [
          "\x{39d}",
          "\x{399}",
          "\x{39a}",
          "\x{39f}",
          'L',
          "\x{39f}",
          'P',
          "\x{39f}",
          "\x{3a5}",
          'L',
          "\x{39f}",
          'S',
          ' ',
          "\x{39d}",
          '.',
          ' ',
          "\x{399}",
          "\x{39f}",
          'A',
          "\x{39d}",
          "\x{39d}",
          'I',
          'S'
        ];
Отсюда видно, что большинство символов юникодные. В принципе, на это можно было б и забить и написать их в такой последовательности: &#n1;&#n2 .... etc, при этом надпись будет отображаться корректно.

Но тогда поиск по такой базе будет невозможен. Символы с виду латинские, а на самом деле совсем нет.

Задача: преобразовать юникодные символы, которые совпадают с латинскими, в нормальную кодировку. Чтобы буква N была 'N' а не «\x{39d}»

В работе я использую perl. Но не побрезгаю, если будет предложено какое-нить иное решение.

Заранее благодарю.


Postgres умеет сам импортировать CSV, может тебе погуглить в этом направлении?

Alve ★★★★★
()

преобразовать юникодные символы, которые совпадают с латинскими, в нормальную кодировку

Это просто заглавные греческие буквы. Напишите сами небольшую табличку для перекодировки.

buddhist ★★★★★
()
say @$VAR1;
print Dumper [ map { charnames::viacode(ord $_) } @$VAR1 ];
say map { encode 'latin1',$_ } @$VAR1;
say map { encode 'iso-8859-7',$_ } @$VAR1;
__END__
ΝΙΚΟLΟPΟΥLΟS Ν. ΙΟAΝΝIS
$VAR1 = [
'GREEK CAPITAL LETTER NU',
'GREEK CAPITAL LETTER IOTA',
'GREEK CAPITAL LETTER KAPPA',
'GREEK CAPITAL LETTER OMICRON',
'LATIN CAPITAL LETTER L',
'GREEK CAPITAL LETTER OMICRON',
'LATIN CAPITAL LETTER P',
'GREEK CAPITAL LETTER OMICRON',
'GREEK CAPITAL LETTER UPSILON',
'LATIN CAPITAL LETTER L',
'GREEK CAPITAL LETTER OMICRON',
'LATIN CAPITAL LETTER S',
'SPACE',
'GREEK CAPITAL LETTER NU',
'FULL STOP',
'SPACE',
'GREEK CAPITAL LETTER IOTA',
'GREEK CAPITAL LETTER OMICRON',
'LATIN CAPITAL LETTER A',
'GREEK CAPITAL LETTER NU',
'GREEK CAPITAL LETTER NU',
'LATIN CAPITAL LETTER I',
'LATIN CAPITAL LETTER S'
];
????L?P??L?S ?. ??A??IS
ÍÉÊÏLÏPÏÕLÏS Í. ÉÏAÍÍIS


Боюсь, такое только руками при помощи tr///.

AITap ★★★★★
()
Ответ на: комментарий от Artificial_Thought

Наверное, набирали в двух раскладках одновременно.

dave ★★★★★
()

Но тогда поиск по такой базе будет невозможен. Символы с виду латинские, а на самом деле совсем нет.

Любопытно. У некоторых элементов массива поднят юникодный флаг и строка в формате UTF-X, а часть строк видимо в латинице (с виду и на самом деле).

outtaspace ★★★
()
Ответ на: комментарий от Alve

Спасибо за совет, но эти данные перед запихиванием в БД надо некоторым образом обработать.

solom
() автор топика

Самое ИМХО правильное решение - считать что мы всегда работаем с UTF, если явно не сказано обратное.

use utf8; # все внутренние строки будут по умолчанию в utf
use Encode;
use open ':utf8';

####################### UTF8 ######################################
my $utf_locale=0;
my $nonutf_locale;

# utf 2 local; используется для подготовки строки к печати на экран
sub utf2lcl($) {
    my $tmp = $_[0];
    #print "utf test: $tmp\n";
    if ( ! $utf_locale) {
        $tmp = encode($nonutf_locale,$tmp);
    }
    return $tmp;
}

# local 2 utf; используется для перевода строки, полученной из
# консоли, в utf
sub lcl2utf($) {
    my $tmp=$_[0];
    if ( ! $utf_locale ) {
        $tmp = decode( $nonutf_locale, $tmp );
    }
    Encode::_utf8_on($tmp);
    return $tmp;
}
#если локаль системы UTF-8, установить соответсвующих binmode для STDOUT, STDERR
if ( $ENV{LANG}=~ /UTF/i ) {
    $utf_locale=1;
    binmode STDOUT, ":utf8";
    binmode STDERR , ":utf8";
} else {
    $nonutf_locale=$ENV{LANG};
}

############# END OF UTF8 ######################################

Для удобства использования

sub print_error($) {
    print STDERR utf2lcl($_[0]),"\n";
}

sub print_log($) {
    print STDOUT utf2lcl($_[0]),"\n";
}
router ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.