Мы работаем! Пишите WhatsApp / Viber / Telegram: +7 951 127-23-57, Skype: creograf

Смена кодировки сайта на perl'e с window-1251 на utf8. Продолжение...

Смена кодировки сайта на perl'e с window-1251 на utf8. Продолжение...

14:09:36 21.02.2011 Комментарии: 1

Описанный ранее автоматический способ перевода сайта на perl'e с виндовской кодировки в юникод разбился об реальность %). Опишу проблемы, с которыми пришлось столкнуться, может быть кому-то пригодится.

1. База данных. В моем случае - это mysql. У каждого скаляра, вынутого из базы данных, должна стоять галочка, что он в utf8. В противном случае не будут работать regexp'ы и проч. Можно помечать их utf8-ом руками: 

  utf8::decode($string_from_db);

Но если применить это к двоичным данным из blob'ов, то что-нибудь может сломаться. Альтернативный вариант - это после соединения с БД сообщить DBI, что данные в utf8.

  $dbh->{'mysql_enable_utf8'} = 1 if($encoding=~/utf/i);

Тогда она должна сама переводить строки в utf8, а blob не трогать. Должна, но на хостинге у nic.ru почему-то то работает, то не работает. Вроде бы в третьей DBI были какие-то косяки с utf8.   
Вот не очень красивый, но эффективный способ это полечить:

my $rusletters = qr{А-Яа-я};
#...
# для всего, что вытаскивается из бд
_fix_utf8($data_from_db); 

#...

# если кодировка utf8, то
# у все, что вытаскивается из БД, нужено пометить, как utf8
sub _fix_utf8 {
	my $arg = shift;
 #   return $arg; #!! off
 	return undef unless ( defined $arg );
	return $arg unless ( $encoding =~ /utf/i );

	unless ( ref $arg ) {
		utf8::decode( $arg ) if (utf8::valid($arg) and !utf8::is_utf8( $arg ) and $arg=~$rusletters);
		return $arg;
	}
	elsif ( ref $arg eq "ARRAY" ) {
		return _fix_utf8_array($arg);
	}
	elsif ( ref $arg eq "HASH" ) {
		die "hash?";
		return _fix_utf8_hash($arg);
	}
	return $arg;
}

sub _fix_utf8_array {
	my $arg = shift;

	return $arg unless ( ref $arg eq "ARRAY" );

	for ( my $i = 0 ; $i < 1 + $#$arg ; $i++ ) {
		$arg->[$i] = _fix_utf8_array( $arg->[$i] )
		  if ( ref $arg->[$i] eq "ARRAY" );
		$arg->[$i] = _fix_utf8( $arg->[$i] ) unless ( ref $arg->[$i] );
	}
	return $arg;
}

Он помечает utf-8 все строки, которые не помечены utf8, и содержат буквы А-Яа-я в юникоде. В общем-то в буквах А-Яа-я вся некрасивость.

2. Во всех модулях, где в качестве значения переменных используется utf-8, надо писать

  use utf8;
  #...
  $param->{ModuleName}="Блог";

Тоже самое, если в модуле выполняются regexp'ы над юникодными строками.

3. Всех параметры http-запросов, кроме файлов, надо декодить в utf8, например так:

  foreach ( $self->{httprequest}->param ) {
    utf8::decode($k);
    if ( $v && !( ref $v && fileno($v) ) ) {
      $k =~ s/\.x//go;
      next if ( $k =~ /\.y/ );
      utf8::decode($v);
    }
    $self->{entry}->{$k} = $v;

4. Отправку писем в utf8 тоже пришлось переписать. Подробности в предыдущем посте

5. Пришлось поправить модуль DBIx::FullIndexSearch. Кому надо, пишите, выложу.

6. При открытии файлов надо указывать, что они в utf8:

  open my $fh, '<:utf8', $tname or die $!;

Похожие записи

02:33:09 11.04.2011
alexchorny
Важно поставить сравнительно свежий DBD::mysql, в старых версиях поддержка Unicode хуже.

Вы можете оставить
комментарий



    
© 2002-2022 Креограф. Все права защищены законом РФ
 Русский /  English