Spec-Zone.ru › Perl 5.34

кодировка

СОДЕРЖАНИЕ

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

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

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

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

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

Под-pragma :locale

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

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

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

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

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

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

ОСОБЕННОСТИ

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

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

  • Без этого pragma, если строки, работающие с байтами, и строки с данными символов Юникода, конкатенируются, новая строка будет создана путём декодирования байтовых строк как 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 (греческая малая буква йота с тоном) слева НЕ будет повышена до \x{3af} (Юникод греческая малая буква йота с тоном) из-за \x{100} слева. Не следует смешивать устаревшие данные и Юникод в одной строке.

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

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

До Perl v5.22

Pragma был лексическим для каждого сценария, а не для каждого блока. Имел значение только последний use encoding или no encoding, и он влиял на весь сценарий. Однако, pragma 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 должен разобрать сценарий перед применением этого pragms, такие кодировки, как 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 получают закодированный поток

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

литералы в регулярных выражениях, длина которых превышает 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–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.34.0/encoding

Spec-Zone.ru

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