кодировка
СОДЕРЖАНИЕ
- ИМЯ
- ПРЕДУПРЕЖДЕНИЕ
- СИНОПСИС
- ОПИСАНИЕ
- ПАРАМЕТРЫ
- ОСОБЕННОСТИ
- ПРИМЕР - 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, например, вы всё равно можете попробовать примеры из Главы 15Programming 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 такова:
-
Если платформа поддерживает интерфейс
langinfo(CODESET), используемый кодировочный набор используется в качестве кодировки по умолчанию для предиката open. -
Если 1. не сработало, но мы находимся внутри предиката локали, переменные окружения
LC_ALLиLANG(в указанном порядке) проверяются на соответствие кодировкам (часть после ".", если она есть), и если какая-либо найдена, она используется в качестве кодировки по умолчанию для предиката open. -
Если 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