Spec-Zone.ru › Perl 5.30

кодировка

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ПРЕДУПРЕЖДЕНИЕ
  • СИНОПСИС
  • ОПИСАНИЕ
  • НАСТРОЙКИ
    • Установка STDIN и/или STDOUT индивидуально
    • Под-псевдоним :locale
  • ЗАМЕЧАНИЯ
    • ПОБОЧНЫЕ ЭФФЕКТЫ
    • НЕ СМЕШИВАЙТЕ НЕСКОЛЬКО КОДИРОВОК
    • До Perl v5.22
    • До версии Encode 1.87
    • До Perl v5.8.1
  • ПРИМЕР - Greekperl
  • ОШИБКИ
  • ИСТОРИЯ
  • СМОТРИТЕ ТАКЖЕ

НАЗВАНИЕ

encoding — позволяет писать скрипты в кодировках, отличных от ASCII и UTF-8

ПРЕДУПРЕЖДЕНИЕ

Этот модуль устарел с версии Perl v5.18. См. "ОПИСАНИЕ" и "ОШИБКИ".

СИНОПСИС

use encoding "greek";  # Perl like Greek to you?
use encoding "euc-jp"; # Jperl!

# or you can even do this if your shell supports your native encoding

perl -Mencoding=latin2 -e'...' # Feeling centrally European?
perl -Mencoding=euc-kr -e'...' # Or Korean?

# more control

# A simple euc-cn => utf-8 converter
use encoding "euc-cn", STDOUT => "utf8";  while(<>){print};

# "no encoding;" supported
no encoding;

# an alternate way, Filter
use encoding "euc-jp", Filter=>1;
# now you can use kanji identifiers -- in euc-jp!

# encode based on the current locale - specialized purposes only;
# fraught with danger!!
use encoding ':locale';

ОПИСАНИЕ

Этот псевдоним используется для того, чтобы Perl-скрипт мог быть написан в кодировках, которые не являются строго ASCII или UTF-8. Он преобразует все или части скрипта Perl из заданной кодировки в UTF-8 и изменяет слои PerlIO для STDIN и STDOUT на указанную кодировку.

Этот псевдоним относится к временам, когда UTF-8-совместимые редакторы были редкостью. Но это было давно, и необходимость в нём сильно уменьшилась. Это, вместе с тем фактом, что он не работает с потоками, а также с другими проблемами (см. "ОШИБКИ"), привели к его устареванию. Планируется удалить этот псевдоним в будущей версии Perl. Новый код следует писать в UTF-8 и использовать псевдоним use utf8 вместо него (см. perluniintro и utf8 для получения подробностей). Старый код следует преобразовать в UTF-8, используя что-то вроде рецепта в "СИНОПСИСЕ" (хотя этот простой подход может потребовать последующих ручных корректировок).

Если UTF-8 не подходит, рекомендуется использовать простой фильтр кодировки, например, тот, который предоставляется модулем Filter::Encoding в CPAN, или собственным параметром Filter этого псевдонима (см. ниже).

Единственное законное использование этого псевдонима — почти наверняка только одно на файл, в начале, со сферой действия файла, так как файл, скорее всего, будет написан только в одной кодировке. В Perls до v5.22 применяются дополнительные ограничения (см. "До Perl v5.22").

Существует два основных режима работы (плюс отключение):

use encoding ['ENCNAME'] ;

Примечание: Этот режим работы больше не поддерживается начиная с Perl v5.26.

Это обычный режим работы. Он преобразует различные литералы, встречающиеся в исходном файле Perl, из кодировки ENCNAME в UTF-8 и аналогично преобразует числовые коды символов. Это используется, когда скрипт является комбинацией ASCII (для имён переменных и знаков препинания и т.д.), но данные литералов находятся в указанной кодировке.

ENCNAME является необязательным. Если он опущен, используется кодировка, указанная в переменной окружения PERL_ENCODING. Если она не установлена или разрешённая кодировка не известна Encode, будет выброшено сообщение об ошибке Unknown encoding 'ENCNAME'.

Начиная с Perl v5.8.6 (Encode версия 2.0.1), ENCNAME может быть именем :locale. Это для очень специализированных приложений и документировано в "Под-псевдониме :locale" ниже.

Литералы, которые преобразуются, — это q//, qq//, qr//, qw///, qx//, а начиная с v5.8.1, — tr///. Операции, которые выполняют преобразования, включают chr, ord, utf8::upgrade (но не utf8::downgrade) и chomp.

Также начиная с v5.8.1, псевдо-файловый дескриптор DATA преобразуется из кодировки в UTF-8.

Например, вы можете написать код на EUC-JP следующим образом:

my $Rakuda = "\xF1\xD1\xF1\xCC"; # Camel in Kanji
             #<-char-><-char->   # 4 octets
s/\bCamel\b/$Rakuda/;

И с use encoding "euc-jp" в эффекте, это то же самое, что и этот код в UTF-8:

my $Rakuda = "\x{99F1}\x{99DD}"; # two Unicode Characters
s/\bCamel\b/$Rakuda/;

См. "ПРИМЕР" ниже для более полного примера.

Если ${^UNICODE} (доступно начиная с v5.8.2) существует и отлично от нуля, слои PerlIO STDIN и STDOUT будут установлены в ":encoding(ENCNAME)". Поэтому

use encoding "euc-jp";
my $message = "Camel is the symbol of perl.\n";
my $Rakuda = "\xF1\xD1\xF1\xCC"; # Camel in Kanji
$message =~ s/\bCamel\b/$Rakuda/;
print $message;

выведет

"\xF1\xD1\xF1\xCC is the symbol of perl.\n"

а не

"\x{99F1}\x{99DD} is the symbol of perl.\n"

Вы можете переопределить это, указав дополнительные аргументы; см. ниже.

Обратите внимание, что STDERR НЕ будет изменено независимо от этого.

Также обратите внимание, что нестандартные файловые дескрипторы останутся без изменений. Используйте use open или binmode для изменения слоёв этих дескрипторов.

use encoding ENCNAME, Filter=>1;

Он работает так же, как выше, но аргумент Filter со значением, отличным от нуля, заставляет весь скрипт, а не только литералы, быть преобразованным из кодировки в UTF-8. Это позволяет идентификаторам в исходном коде также быть в этой кодировке. (Проблемы могут возникнуть, если кодировка не является надмножеством ASCII; представьте себе, что все ваши точки с запятой переводятся в что-то другое.) Вы можете использовать этот вариант, чтобы заставить

${"\x{4eba}"}++

работать. (Это эквивалентно $human++, где human — один иероглиф.)

Это фактически означает, что ваш исходный код ведёт себя так, как будто он был написан в UTF-8 с 'use utf8 в силе. Так что даже если ваш редактор поддерживает только Shift_JIS, например, вы всё равно можете попробовать примеры из главы 15 Programming Perl, 3rd Ed..

Этот вариант значительно медленнее, чем другой.

no encoding;

Сбрасывает кодировку скрипта. Слои STDIN, STDOUT сбрасываются до ":raw" (по умолчанию — необработанный поток байтов).

НАСТРОЙКИ

Установка STDIN и/или STDOUT индивидуально

Кодировки STDIN и STDOUT могут быть установлены индивидуально параметрами псевдонима:

use encoding 'euc-tw', STDIN => 'greek'  ...;

В этом случае вы не можете опустить первый ENCNAME. STDIN => undef полностью отключает преобразование ввода-вывода для данного файлового дескриптора.

Когда ${^UNICODE} (доступно начиная с v5.8.2) существует и отлично от нуля, эти параметры будут полностью проигнорированы. См. "${^UNICODE}" в perlvar и "-C" в perlrun для подробностей.

Под-псевдоним :locale

Начиная с v5.8.6, имя кодировки может быть :locale. Это означает, что кодировка берётся из текущего региональных настроек, а не жёстко задаётся псевдонимом. Поскольку скрипт действительно может быть закодирован только в одной кодировке, этот параметр опасен. Он имеет смысл только в том случае, если сам скрипт написан на ASCII, и все возможные региональные настройки, которые будут использоваться при выполнении скрипта, являются надмножествами ASCII. Это означает, что сам скрипт не изменяется, но файловые дескрипторы получают указанную кодировку, а операции, такие как chr и ord, используют эту кодировку.

Логика определения региональных настроек :locale, которые использует:

  1. Если платформа поддерживает интерфейс langinfo(CODESET), используется кодировка, возвращённая как значение по умолчанию для псевдонима open.

  2. Если 1. не сработало, но мы находимся в псевдониме locale, переменные среды LC_ALL и LANG (в указанном порядке) сравниваются с кодировками (часть после ".", если таковая имеется), и если найдено совпадение, это используется в качестве кодировки по умолчанию для псевдонима open.

  3. Если 1. и 2. не сработали, переменные среды LC_ALL и LANG (в указанном порядке) сравниваются на предмет чего-либо, похожего на UTF-8, и если найдено совпадение, :utf8 используется в качестве кодировки по умолчанию для псевдонима open.

Если ваши переменные среды региональных настроек (LC_ALL, LC_CTYPE, LANG) содержат строки 'UTF-8' или 'UTF8' (регистронезависимое сравнение), кодировка по умолчанию для вашего STDIN, STDOUT, и STDERR, и любого последующего открытия файла, будет UTF-8.

ЗАМЕЧАНИЯ

ПОБОЧНЫЕ ЭФФЕКТЫ

  • Если псевдоним encoding находится в области видимости, то возвращаемые длины вычисляются из длины $/ в символах Юникода, что не всегда совпадает с длиной $/ в родной кодировке.

  • Без этого псевдонима, если строки, работающие с байтами, и строки с данными символов Юникода конкатенируются, новая строка будет создана путём декодирования строк байтов как ISO 8859-1 (Latin-1).

    Псевдоним encoding изменяет это, используя указанную кодировку вместо неё. Например:

    use encoding 'utf8';
    my $string = chr(20000); # a Unicode string
    utf8::encode($string);   # now it's a UTF-8 encoded byte string
    # concatenate with another Unicode string
    print length($string . chr(20000));

    Выведет 2, потому что $string улучшается до UTF-8. Без use encoding 'utf8';, он выведет 4 вместо этого, так как $string состоит из трёх октетов при интерпретации как Latin-1.

НЕ СМЕШИВАЙТЕ НЕСКОЛЬКО КОДИРОВОК

Обратите внимание, что только литералы (строки или регулярные выражения), содержащие только устаревшие кодовые точки, подвергаются воздействию: если вы смешиваете данные такого типа

\x{100}\xDF
\xDF\x{100}

данные предполагаются в (Latin 1 и) Юникоде, а не в вашей родной кодировке. Другими словами, это будет соответствовать в "греческом":

"\xDF" =~ /\x{3af}/

но это не будет

"\xDF\x{100}" =~ /\x{3af}\x{100}/

поскольку \xDF (ISO 8859-7 GREEK SMALL LETTER IOTA WITH TONOS) слева не будет обновлено до \x{3af} (Unicode GREEK SMALL LETTER IOTA WITH TONOS) из-за \x{100} слева. Вам не следует смешивать устаревшие данные и Юникод в одной строке.

Этот пragma также влияет на кодировку диапазона кодовых точек 0x80..0xFF: обычно символы в этом диапазоне остаются байтами по 8 бит (если они не сочетаются с символами с кодовыми точками 0x100 или больше, в этом случае все символы должны быть закодированы в UTF-8), но если пragma encoding присутствует, то даже диапазон 0x80..0xFF всегда кодируется в UTF-8.

В конце концов, самое лучшее в этом pragma то, что вам не нужно прибегать к \x{....}, чтобы просто написать своё имя в родной кодировке. Поэтому не стесняйтесь помещать свои строки в кодировке в кавычки и в выражениях regex.

До Perl v5.22

Pragma был лексическим по всему скрипту, а не по блокам. Только последний use encoding или no encoding имел значение, и он влиял на весь скрипт. Однако, пragma no encoding поддерживался и use encoding мог появляться в данном скрипте любое количество раз (хотя эффективным был только последний).

Поскольку область действия не была лексической, использование chr, ord, и т.д. другими модулями, тоже влияло. Это приводило к странным и неверным действиям на расстоянии, которые трудно отлаживать.

Это означает, что вам нужно быть очень внимательным к порядку загрузки:

# called module
package Module_IN_BAR;
use encoding "bar";
# stuff in "bar" encoding here
1;

# caller script
use encoding "foo"
use Module_IN_BAR;
# surprise! use encoding "bar" is in effect.

Лучший способ избежать этой странности — использовать этот pragma СРАЗУ после загрузки других модулей. Т.е.

use Module_IN_BAR;
use encoding "foo";

До версии Encode 1.87

  • STDIN и STDOUT не устанавливались в опции фильтра. А STDIN=>ENCODING и STDOUT=>ENCODING работали не так, как в версии без фильтра.

  • use utf8 не объявлялся неявно, поэтому вам нужно use utf8 для выполнения

    ${"\x{4eba}"}++

До Perl v5.8.1

"NON-EUC" кодировки с двойным байтом

Так как Perl нужно проанализировать скрипт до применения этого pragma, такие кодировки, как Shift_JIS и Big-5, которые могут содержать '\' (обратный слэш; \x5c) во втором байте, терпят неудачу, потому что второй байт может случайно экранировать следующий символ кавычки.

tr///

Pragma encoding работает, декодируя литералы строк в q//,qq//,qr//,qw///, qx// и так далее. В Perl v5.8.0 это не относится к tr///. Поэтому,

use encoding 'euc-jp';
#....
$kana =~ tr/\xA4\xA1-\xA4\xF3/\xA5\xA1-\xA5\xF3/;
#           -------- -------- -------- --------

Не работает как

$kana =~ tr/\x{3041}-\x{3093}/\x{30a1}-\x{30f3}/;
Легенда символов выше
utf8     euc-jp   charnames::viacode()
-----------------------------------------
\x{3041} \xA4\xA1 HIRAGANA LETTER SMALL A
\x{3093} \xA4\xF3 HIRAGANA LETTER N
\x{30a1} \xA5\xA1 KATAKANA LETTER SMALL A
\x{30f3} \xA5\xF3 KATAKANA LETTER N

Это нелогичное поведение исправлено в Perl v5.8.1.

В Perl v5.8.0 вы можете обойти это следующим образом;

use encoding 'euc-jp';
#  ....
eval qq{ \$kana =~ tr/\xA4\xA1-\xA4\xF3/\xA5\xA1-\xA5\xF3/ };

Обратите внимание, что выражение tr// заключено в qq{}. Идея в том же, что и в классическом приёме, который позволяет tr/// 'интерполировать':

tr/$from/$to/;            # wrong!
eval qq{ tr/$from/$to/ }; # workaround.

ПРИМЕР - Greekperl

use encoding "iso 8859-7";

# \xDF in ISO 8859-7 (Greek) is \x{3af} in Unicode.

$a = "\xDF";
$b = "\x{100}";

printf "%#x\n", ord($a); # will print 0x3af, not 0xdf

$c = $a . $b;

# $c will be "\x{3af}\x{100}", not "\x{df}\x{100}".

# chr() is affected, and ...

print "mega\n"  if ord(chr(0xdf)) == 0x3af;

# ... ord() is affected by the encoding pragma ...

print "tera\n" if ord(pack("C", 0xdf)) == 0x3af;

# ... as are eq and cmp ...

print "peta\n" if "\x{3af}" eq  pack("C", 0xdf);
print "exa\n"  if "\x{3af}" cmp pack("C", 0xdf) == 0;

# ... but pack/unpack C are not affected, in case you still
# want to go back to your native encoding

print "zetta\n" if unpack("C", (pack("C", 0xdf))) == 0xdf;

ОШИБКИ

Безопасность потоков

use encoding ... не является потокобезопасным (т.е. не используйте в потоковых приложениях).

Нельзя использовать более чем в одном модуле в одной программе.

Разрешена только одна кодировка. Если вы объединяете модули в программе, которые имеют разные кодировки, будет использоваться только одна.

Другие модули, использующие STDIN и STDOUT получают закодированный поток

Они могут ожидать совершенно другого.

Литералы в regex, превышающие 127 байт

Для собственных многобайтовых кодировок (фиксированной или переменной длины) текущая реализация регулярных выражений может вызвать ошибки перекодировки для литералов регулярных выражений, превышающих 127 байт.

EBCDIC

Pragma encoding не поддерживается на платформах EBCDIC.

format

Этот pragma не очень хорошо работает с format, потому что PerlIO плохо с ним сочетается. Когда format содержит не-ASCII символы, он печатает странные символы или генерирует "предупреждения о символах с большой шириной". Чтобы понять это, попробуйте код ниже.

# Save this one in utf8
# replace *non-ascii* with a non-ascii string
my $camel;
format STDOUT =
*non-ascii*@>>>>>>>
$camel
.
$camel = "*non-ascii*";
binmode(STDOUT=>':encoding(utf8)'); # bang!
write;              # funny
print $camel, "\n"; # fine

Без binmode это работает, но без binmode print() терпит неудачу вместо write().

В любом случае, само использование format сомнительно в отношении символов Unicode, так как нужно учитывать такие вещи, как ширина символов (например, двойная ширина для иероглифов) и направления (например, BIDI для арабского и иврита).

См. также "ОСОБЕННОСТИ"

ИСТОРИЯ

Этот pragma впервые появился в Perl v5.8.0. Он был улучшен в последующих версиях, как указано выше.

См. также

perlunicode, Encode, open, Filter::Util::Call,

Гл. 15 в Programming Perl (3rd Edition) Ларри Уолла, Тома Кристиансена, Джона Орванта; O'Reilly & Associates; ISBN 0-596-00027-8

© 1993–2020 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.30.3/encoding

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API