Spec-Zone.ru › Perl 5.36

кодировка

СОДЕРЖАНИЕ

  • ИМЯ
  • ПРЕДУПРЕЖДЕНИЕ
  • СИНОПСИС
  • ОПИСАНИЕ
  • ПАРАМЕТРЫ
    • Указание 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 данного предиката (см. ниже).

Единственное обоснованное использование этого предиката, скорее всего, только одно на файл, в начале, со значением file scope, поскольку файл, скорее всего, будет написан только в одной кодировке. Дополнительные ограничения применяются в 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 НЕ будет изменено независимо.

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

use encoding ENCNAME, Filter=>1;

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

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

работало. (Это эквивалентно $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. не сработало, но мы находимся внутри предиката локали, переменные окружения 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 находится в области действия, то возвращаемые длины вычисляются из длины $/ в символах Юникода, что не всегда совпадает с длиной $/ в исходной кодировке.

  • Без этого предиката, если строки, работающие с байтовыми значениями, и строки с данными Unicode-символов, конкатенируются, новая строка будет создана путем декодирования байтовых строк как 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 и) Unicode, а не в вашей кодировке по умолчанию. Другими словами, это будет соответствовать в "греческом":

"\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} слева. Не следует смешивать устаревшие данные и Unicode в одной строке.

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

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

Прежде чем использовать Perl v5.22

Предикат применялся на уровне всего скрипта, а не блока. Важны только последний use encoding или no encoding, и он влиял на весь скрипт. Однако, предикат 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.

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

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 нужно проанализировать скрипт перед применением этого предиката, такие кодировки, как Shift_JIS и Big-5, которые могут содержать '\' (обратный слэш; \x5c) во втором байте, терпят неудачу, так как второй байт случайно может экранировать символ кавычки, за которым следует.

tr///

Предикат 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 получают закодированный поток

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

литералы в регулярных выражениях, которые длиннее 127 байт

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

EBCDIC

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

format

Этот предикат не работает хорошо с 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 вызывает сомнения в отношении символов Юникода, поскольку вам нужно учитывать такие вещи, как ширина символов (например, двойная ширина для иероглифов) и направления (например, BIDI для арабского и иврита).

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

ИСТОРИЯ

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

См. также

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

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

© 1993–2021 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.36.0/encoding

Spec-Zone.ru

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