Spec-Zone.ru › Perl 5.38

кодировка

СОДЕРЖАНИЕ

  • НАЗВАНИЕ
  • ПРЕДУПРЕЖДЕНИЕ
  • СИНОПСИС
  • ОПИСАНИЕ
  • ПАРАМЕТРЫ
    • Настройка STDIN и/или STDOUT индивидуально
    • Под-pragma :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';

ОПИСАНИЕ

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

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

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

Единственным законным использованием этого pragmy, почти наверняка, является одно использование на файл, в начале файла, так как файл, скорее всего, будет написан только в одной кодировке. Дополнительные ограничения действуют в Perl'ях до версии 5.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. Это предназначено для очень специализированных применений и документировано в "Под-pragma :locale" ниже.

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

Также начиная с версии 5.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 можно индивидуально задать параметрами pragmy:

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

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

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

Под-pragma :locale

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

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

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

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

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

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

ЗАМЕЧАНИЯ

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

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

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

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

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

В конечном счете, лучшее в этом pragma — это то, что вам не придётся прибегать к \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///

Предикат кодировки работает путем декодирования строковых литералов в 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

Предикат кодирования не поддерживается на платформах 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 вместо write() используется print().

В любом случае, само использование 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–2023 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.38.0/encoding

Spec-Zone.ru

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