perllocale
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- ЧТО ТАКОЕ ЛОКАЛЬ
- ПРЕДВАРИТЕЛЬНАЯ НАСТРОЙКА ДЛЯ ИСПОЛЬЗОВАНИЯ ЛОКАЛЕЙ
- ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ
- Предикат «use locale»
- Функция setlocale
- Многопоточная работа
- Поиск локалей
- ПРОБЛЕМЫ С ЛОКАЛЯМИ
- Тестирование на наличие неисправных локалей
- Временное исправление проблем с локалями
- Постоянное исправление проблем с локалями
- Постоянное исправление конфигурации локалей вашей системы
- Исправление конфигурации локалей системы
- Функция localeconv
- I18N::Langinfo
- КАТЕГОРИИ ЛОКАЛЕЙ
- БЕЗОПАСНОСТЬ
- ОКРУЖЕНИЕ
- ПРИМЕЧАНИЯ
- Unicode и UTF-8
- ОШИБКИ
- СМОТРИ ТАКЖЕ
- ИСТОРИЯ
НАЗВАНИЕ
perllocale - Обработка локалей Perl (интернационализация и локализация)
ОПИСАНИЕ
Вначале был ASCII, «American Standard Code for Information Interchange», который довольно хорошо работает для американцев с их английским алфавитом и валютой в долларах. Но он работает не очень хорошо даже для других англоговорящих, которые могут использовать разные валюты, такие как британский фунт (так как символ этой валюты отсутствует в ASCII); и он совершенно непригоден для многих тысяч других языков мира.
Для решения этих недостатков была изобретена концепция локалей (формально ISO C, XPG4, POSIX 1.c «система локалей»). И приложения пишутся и пишутся с использованием механизма локалей. Процесс адаптации такого приложения к предпочтениям пользователей в этом типе вопросов называется интернационализацией (часто сокращенно i18n); информирование такого приложения об определенном наборе предпочтений известно как локализация (l10n).
Perl был расширен для поддержки определенных типов локалей, доступных в системе локалей. Это управляется на уровне приложения с использованием одного предикатива, одного вызова функции и нескольких переменных среды.
Perl поддерживает однобайтовые локали, являющиеся супермножествами ASCII, такие как ISO 8859, и одну многобайтовую локаль типа UTF-8, описанную в следующем абзаце. Perl не поддерживает другие многобайтовые локали, такие как локали для восточноазиатских языков.
К сожалению, в конструкции (и часто в реализациях) локалей есть довольно много недостатков. Unicode был изобретён (см. perlunitut для введения в него), частично для решения этих недостатков конструкции, и в наши дни есть ряд «UTF-8 локалей», основанных на Unicode. Это локали, в наборе символов которых используется Unicode, закодированный в UTF-8. Начиная с версии 5.20, Perl полностью поддерживает UTF-8 локали, за исключением сортировки и сравнения строк, таких как lt и ge. Начиная с v5.26, Perl может обрабатывать их приемлемо, в зависимости от реализации платформы. Однако для более ранних выпусков или для лучшего контроля используйте Unicode::Collate. Perl по-прежнему поддерживает старые локали, отличные от UTF-8. В настоящее время нет UTF-8 локалей для платформ EBCDIC.
(Unicode также создаёт CLDR, «Общий репозиторий данных для локалей», http://cldr.unicode.org/, который включает больше типов информации, чем доступно в системе локалей POSIX. На момент написания этой статьи не было модуля CPAN, который предоставлял бы доступ к этим данным, закодированным в XML. Однако возможно вычислить данные локали POSIX из них, и более ранние версии CLDR уже извлекали их для вас в виде UTF-8 локалей http://unicode.org/Public/cldr/2.0.1/.)
ЧТО ТАКОЕ ЛОКАЛЬ
Локаль — это набор данных, описывающий различные аспекты того, как различные сообщества мира классифицируют свой мир. Эти категории разбиваются на следующие типы (некоторые из них содержат краткое описание здесь):
-
Категория
LC_NUMERIC: Форматирование чисел -
Это указывает, как числа должны быть отформатированы для лучшей читаемости, например, символ, используемый в качестве десятичной точки.
-
Категория
LC_MONETARY: Форматирование денежных сумм -
Категория
LC_TIME: Форматирование даты и времени -
Категория
LC_MESSAGES: Сообщения об ошибках и другие сообщения -
Это используется только самим Perl для доступа к сообщениям об ошибках операционной системы через $! и $^E.
-
Категория
LC_COLLATE: Сортировка -
Это указывает порядок букв для сравнения и сортировки. В латинских алфавитах, например, «b» обычно следует за «a».
-
Категория
LC_CTYPE: Типы символов -
Это указывает, например, является ли символ заглавной буквой.
- Другие категории
-
Некоторые платформы имеют другие категории, связанные с такими вещами, как единицы измерения и размеры бумаги. Ни одна из них не используется непосредственно Perl, но внешние операции, с которыми Perl взаимодействует, могут их использовать. См. "Не входит в область действия "use locale"" ниже.
Более подробная информация о категориях, используемых Perl, приведена ниже в "КАТЕГОРИИ ЛОКАЛЕЙ".
Вместе эти категории в значительной степени позволяют настроить одно приложение для работы во многих разных местах. Но есть недостатки, поэтому продолжайте читать.
ПРЕДВАРИТЕЛЬНАЯ НАСТРОЙКА ДЛЯ ИСПОЛЬЗОВАНИЯ ЛОКАЛЕЙ
Сам Perl (вне модуля POSIX) не будет использовать локали, если его об этом не попросить (но обратите внимание, что Perl может взаимодействовать с кодом, который их использует). Даже если такой запрос есть, все из следующего должно быть истинным для его правильной работы:
-
Ваша операционная система должна поддерживать систему локалей. Если это так, вы должны обнаружить, что функция
setlocale()является документированной частью ее библиотеки C. -
Определения локалей, которые вы используете, должны быть установлены. Вы или ваш системный администратор должны убедиться, что это так. Доступные локали, место их хранения и способ их установки зависят от системы. Некоторые системы предоставляют только несколько жестко запрограммированных локалей и не позволяют добавлять больше. Другие позволяют добавлять «готовые» локали, предоставленные поставщиком системы. Другие позволяют вам или системному администратору определять и добавлять произвольные локали. (Возможно, вам придется попросить вашего поставщика предоставить готовые локали, которые не поставляются с вашей операционной системой.) Обратитесь к документации вашей системы для получения дополнительной информации.
-
Perl должен считать, что система локалей поддерживается. Если это так, то
perl -V:d_setlocaleскажет, что значениеd_setlocaleравноdefine.
Если вы хотите, чтобы приложение Perl обрабатывало и отображало ваши данные в соответствии с определенной локалью, код приложения должен включать предикат use locale (см. "Предикат «use locale»") при необходимости, и по крайней мере одно из следующего должно быть истинным:
-
Переменные среды, определяющие локаль (см. "ОКРУЖЕНИЕ") должны быть правильно настроены на момент запуска приложения, либо вами, либо тем, кто настраивал вашу учетную запись системы; или
-
Приложение должно установить свою собственную локаль, используя метод, описанный в "Функции setlocale".
ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ
The "use locale" pragma
Начиная с Perl 5.28, этот прагма может использоваться в многопоточных приложениях на системах, которые поддерживают многопоточную работу с локалью. Применяются некоторые ограничения, см. "Многопоточные" ниже. На системах без этой возможности или в более ранних версиях Perl, НЕ используйте этот прагма в скриптах с несколькими активными потоками. В этих случаях локализация не локальна для отдельного потока. Другой поток может изменить локаль в любой момент, что может привести, как минимум, к тому, что данный поток работает в локали, в которой он не ожидал оказаться. На некоторых платформах также могут возникать ошибки segfaults. Изменение локали не обязательно должно быть явным; некоторые операции заставляют Perl изменять локаль самостоятельно. Вы уязвимы просто тем, что выполнили "use locale".
По умолчанию, сам Perl (вне модуля POSIX) игнорирует текущую локаль. Прагма use locale сообщает Perl использовать текущую локаль для некоторых операций. Начиная с версии 5.16, в этой прагме есть необязательные параметры, описанные ниже, которые ограничивают операции, на которые она влияет.
Текущая локализация устанавливается во время выполнения функцией setlocale(), описанной ниже. Если эта функция еще не была вызвана в ходе выполнения программы, текущая локализация — это та, которая была определена "Окружением" на момент запуска программы. Если нет корректной среды, текущая локализация — это значение, заданное по умолчанию на системе. В системах POSIX, скорее всего, но не обязательно, это локализация "C". В Windows, значение по умолчанию устанавливается через Control Panel->Regional and Language Options компьютера (или его текущий эквивалент).
Операции, на которые влияет локализация:
-
Не в рамках действия
"use locale" -
Только определённые операции (все исходящие за пределами Perl) должны быть затронуты, как следует:
-
Текущая локализация используется при выходе за пределы Perl с операциями, такими как system() или qx//, если эти операции чувствительны к локали.
-
Также Perl предоставляет доступ к различным функциям библиотеки C через модуль POSIX. Некоторые из этих функций всегда зависят от текущей локали. Например,
POSIX::strftime()используетLC_TIME;POSIX::strtod()используетLC_NUMERIC;POSIX::strcoll()иPOSIX::strxfrm()используютLC_COLLATE. Все такие функции будут вести себя в соответствии с текущей локальностью, даже если эта локализация не отображается в пространстве Perl.Это также относится к I18N::Langinfo.
-
Модули XS для всех категорий, кроме
LC_NUMERICполучают базовую локаль, и, следовательно, любые функции библиотеки C, которые они вызывают, будут использовать эту базовую локаль. Более подробное обсуждение см. в "ПРИМЕЧАНИЯ" в perlxs.
Обратите внимание, что все программы на C (включая интерпретатор Perl, написанный на C) всегда имеют базовую локаль. Эта локализация — "C", если её не изменить вызовом setlocale(). При запуске Perl он изменяет базовую локаль на ту, которая указана в "ОКРУЖЕНИЕ". При использовании модуля POSIX или написании кода XS важно помнить, что базовая локализация может быть чем-то другим, кроме "C", даже если программа явно её не изменила.
-
-
Остаточные эффекты
use locale -
Некоторые операции Perl, настроенные в рамках действия
use locale, сохраняют это действие даже за пределами области. К ним относятся:-
Формат вывода write() определяется более ранним объявлением формата ("формат" в perlfunc), поэтому то, будет ли вывод затронут локализацией, определяется тем, находится ли
format()в области действияuse locale, а не тем, находится лиwrite()в этой области. -
Шаблоны регулярных выражений могут быть скомпилированы с помощью qr// с отложенным фактическим сопоставлением на более поздний этап. Снова, именно то, было ли компилирование выполнено в рамках действия
use locale, определяет поведение сопоставления, а не то, выполняются ли сопоставления в такой области или нет.
-
-
Под
"use locale"; -
-
Все вышеперечисленные операции
-
Объявления форматов ("формат" в perlfunc) и, следовательно, любые последующие
write()используютLC_NUMERIC. -
Преобразование строк и вывод используют
LC_NUMERIC. К ним относятся результатыprint(),printf(),say()иsprintf(). -
Операторы сравнения (
lt,le,cmp,geиgt) используютLC_COLLATE.sort()также затронут, если он используется без явной функции сравнения, поскольку он по умолчанию используетcmp.Примечание:
eqиneне подвержены влиянию локали: они всегда выполняют посимвольное сравнение своих скалярных операндов. Более того, еслиcmpобнаружит, что его операнды равны согласно порядку сортировки, заданному текущей локалью, он переходит к посимвольному сравнению и возвращает 0 (равно) только если операнды идентичны посимвольно. Если вам действительно нужно узнать, равны ли две строки (которыеeqиcmpмогут считать разными) с точки зрения сортировки в локали, см. обсуждение в "КатегорияLC_COLLATE: Сортировка". -
Функции регулярных выражений и изменения регистра (
uc(),lc(),ucfirst()иlcfirst()) используютLC_CTYPE -
Переменные $! (и их синонимы
$ERRNOи$OS_ERROR) и $^E (и его синоним$EXTENDED_OS_ERROR) при использовании в качестве строк используютLC_MESSAGES.
-
Исходное поведение восстанавливается с помощью прагмы no locale или при достижении конца блока, содержащего use locale. Обратите внимание, что вызовы use locale могут быть вложены, и что то, что действует внутри внутреннего диапазона, вернётся к правилам внешнего диапазона в конце внутреннего.
Строковый результат любой операции, использующей информацию о локали, помечен как потенциально небезопасный, так как локали могут быть ненадежными. См. "БЕЗОПАСНОСТЬ".
Начиная с Perl v5.16 в очень ограниченном виде, а более широко в v5.22, вы можете ограничить, какие категории или категории включены в этот конкретный экземпляр прагмы, добавив к нему параметры. Например,
use locale qw(:ctype :numeric); включает локальную осведомленность в своей области только тех операций (перечисленных выше), которые затронуты LC_CTYPE и LC_NUMERIC.
Возможные категории: :collate, :ctype, :messages, :monetary, :numeric, :time и псевдо-категория :characters (описанная ниже).
Таким образом, вы можете сказать
use locale ':messages'; и только $! и $^E будут учитывать локаль. Всё остальное не затронуто.
Поскольку Perl сейчас ничего не делает с категорией LC_MONETARY, указание :monetary фактически ничего не делает. Некоторые системы имеют другие категории, такие как LC_PAPER, но Perl также ничего с ними не делает, и нет способа указать их в аргументах этой прагмы.
Вы также можете легко сказать, чтобы использовать все категории, кроме одной, например,
use locale ':!ctype';
use locale ':not_ctype'; оба из которых означают включение локальной осведомлённости всех категорий, кроме LC_CTYPE. В форме с отрицанием может быть указан только один аргумент категории.
Прежде чем версия 5.22 была доступна только один вариант прагмы с аргументами:
use locale ':not_characters'; (и вы должны сказать not_; вы не можете использовать форму с восклицательным знаком !). Эта псевдокатегория — сокращение для указания и :collate, и :ctype. Следовательно, в форме с отрицанием это почти то же самое, что сказать
use locale qw(:messages :monetary :numeric :time); Мы используем термин «почти», потому что :not_characters также включает use feature 'unicode_strings' в своей области. Этот вариант менее полезен в v5.20 и более поздних версиях и подробно описан в "Unicode и UTF-8", но кратко, он сообщает Perl не использовать символьные части определения локали, то есть категории LC_CTYPE и LC_COLLATE. Вместо этого он будет использовать родную кодировку символов (расширенную Unicode). При использовании этого параметра вы отвечаете за перевод внешней кодировки символов в родную/Unicode (что уже будет, если это одна из всё более популярных локалей UTF-8). Для этого есть удобные способы, описанные в "Unicode и UTF-8".
Функция setlocale
ВНИМАНИЕ! До Perl 5.28 или на системах, не поддерживающих многопоточную работу с локализацией, НЕ используйте эту функцию в потоке. Локализация изменится во всех других потоках одновременно, и если ваш поток будет приостановлен операционной системой, а другой запущен, этот поток не получит ожидаемую локаль. На некоторых платформах может возникнуть гонка, приводящая к ошибкам segfaults, если две нити почти одновременно вызывают эту функцию.
Вы можете переключаться между локалями столько раз, сколько захотите, во время выполнения с помощью функции POSIX::setlocale():
# Import locale-handling tool set from POSIX module.
# This example uses: setlocale -- the function call
# LC_CTYPE -- explained below
# (Showing the testing for success/failure of operations is
# omitted in these examples to avoid distracting from the main
# point)
use POSIX qw(locale_h);
use locale;
my $old_locale;
# query and save the old locale
$old_locale = setlocale(LC_CTYPE);
setlocale(LC_CTYPE, "fr_CA.ISO8859-1");
# LC_CTYPE now in locale "French, Canada, codeset ISO 8859-1"
setlocale(LC_CTYPE, "");
# LC_CTYPE now reset to the default defined by the
# LC_ALL/LC_CTYPE/LANG environment variables, or to the system
# default. See below for documentation.
# restore the old locale
setlocale(LC_CTYPE, $old_locale); Первый аргумент функции setlocale() задаёт категорию, второй — локаль. Категория указывает, в каком аспекте обработки данных необходимо применять правила, специфичные для локали. Имена категорий обсуждаются в "КАТЕГОРИИ ЛОКАЛИ" и "ОКРУЖЕНИЕ". Локаль — это имя набора данных настройки, соответствующее определенной комбинации языка, страны или региона и набора символов. Читайте далее, чтобы узнать советы по наименованию локалей: не все системы называют локали как в примере.
Если второй аргумент не указан, а категория отличается от LC_ALL, функция возвращает строку, обозначающую текущий локаль для категории. Вы можете использовать это значение в качестве второго аргумента в последующем вызове setlocale(), но на некоторых платформах эта строка непрозрачна, и большинство людей не смогут понять, какой локаль она означает.
Если второй аргумент не указан, а категория равна LC_ALL, результат зависит от реализации. Он может представлять собой строку, состоящую из конкатенированных названий локалей (разделитель также зависит от реализации), или одно имя локали. Обратитесь к странице справки setlocale(3) для получения подробностей.
Если второй аргумент указан и соответствует допустимому локали, локаль для категории устанавливается в это значение, и функция возвращает текущее значение локали. Вы можете использовать это значение в ещё одном вызове setlocale(). (В некоторых реализациях возвращаемое значение может иногда отличаться от значения, которое вы передали в качестве второго аргумента — представьте это как псевдоним для переданного вами значения.)
Как показывает пример, если второй аргумент — пустая строка, локаль категории возвращается к значению по умолчанию, заданному соответствующими переменными среды. Обычно это приводит к возврату значения по умолчанию, которое было активным при запуске Perl: изменения в среде, внесённые приложением после запуска, могут или не могут быть замечены, в зависимости от C-библиотеки вашей системы.
Обратите внимание, что когда указывается форма use locale, которая не включает все категории, Perl игнорирует исключённые категории.
Если set_locale() по какой-либо причине завершается неудачно (например, при попытке установить локаль, неизвестную системе), локаль для категории не изменяется, и функция возвращает undef.
Начиная с Perl 5.28, в многопотоковых Perl, скомпилированных на системах, которые реализуют безопасные для потоков операции с локалью POSIX 2008, эта функция фактически не вызывает системную функцию setlocale. Вместо этого используются эти безопасные для потоков операции, чтобы эмулировать функцию setlocale в безопасном для потоков режиме.
Для получения дополнительной информации о категориях обратитесь к setlocale(3).
Многопоточная работа
Начиная с Perl 5.28, поддерживается многопоточная работа с локалями на системах, которые реализуют либо операции с безопасными для потоков локалями POSIX 2008, либо специфичные для Windows. Многие современные системы, такие как различные варианты Unix и Darwin, обладают этим.
Вы можете определить, безопасна ли работа с локалями на вашей системе, посмотрев на переменную только для чтения ${^SAFE_LOCALES}. Значение равно 1, если Perl не многопоточный или использует безопасные для потоков операции с локалями.
Безопасные для потоков операции поддерживаются в Windows, начиная с Visual Studio 2005, и на системах, совместимых с POSIX 2008. Некоторые платформы заявляют о поддержке POSIX 2008, но имеют некорректные реализации, из-за чего файлы подсказок для компиляции под них отключают попытку использования безопасной для потоков поддержки. ${^SAFE_LOCALES} будет равно 0 на таких платформах.
Учитывайте, что приложение с многопоточностью не будет переносимым на платформы, не имеющие встроенной поддержки безопасных для потоков локалей. На системах, которые обладают ею, вы автоматически получаете это поведение для многопоточных Perl, ничего не делая. Если по какой-либо причине вы не хотите использовать эту возможность (возможно, поддержка POSIX 2008 на вашей системе имеет ошибки), вы можете вручную скомпилировать Perl, используя старую, не безопасную для потоков реализацию, передав аргумент -Accflags='-DNO_THREAD_SAFE_LOCALE' в Configure. За исключением Windows, это будет по-прежнему использовать некоторые функции POSIX 2008 в определённых ситуациях. Если они некорректны, вы можете передать следующее в Configure вместо или дополнительно: -Accflags='-DNO_POSIX_2008_LOCALE'. Это также предотвратит использование безопасных для потоков локалей. ${^SAFE_LOCALES} будет равно 0 на системах, которые отключают безопасные для потоков операции.
Изначальная программа запускается с использованием локали, заданной из среды, как описано в "СРЕДА". Все новые потоки запускаются с LC_ALL установленным на "C">. Каждый поток может использовать POSIX::setlocale() для запроса или изменения своей локали в любое время без влияния на другие потоки. Все операции, зависящие от локали, автоматически используют локаль своего потока.
Это должно быть полностью прозрачно для любых приложений, написанных полностью на Perl (за исключением нескольких редко встречающихся нюансов, указанных в разделе "Многопоточная"). Информация для авторов XS-модулей приведена в разделе "Локализованный XS-код" в perlxs.
Поиск локалей
Для доступных на вашей системе локалей также обратитесь к setlocale(3), чтобы увидеть, приводит ли это к списку доступных локалей (поищите раздел SEE ALSO). Если это не сработает, попробуйте следующие команды:
locale -a
nlsinfo
ls /usr/lib/nls/loc
ls /usr/lib/locale
ls /usr/lib/nls
ls /usr/share/locale и посмотрите, отображают ли они что-то похожее на это
en_US.ISO8859-1 de_DE.ISO8859-1 ru_RU.ISO8859-5
en_US.iso88591 de_DE.iso88591 ru_RU.iso88595
en_US de_DE ru_RU
en de ru
english german russian
english.iso88591 german.iso88591 russian.iso88595
english.roman8 russian.koi8r К сожалению, хотя вызов функции setlocale() стандартизирован, имена локалей и каталоги, где хранится конфигурация, не стандартизированы. Основной формат имени — язык_регион.кодировка, но последние части после язык не всегда присутствуют. Язык и страна обычно берутся из стандартов ISO 3166 и ISO 639, соответственно двухбуквенных сокращений для стран и языков мира. Часть кодировка часто упоминает набор символов ISO 8859, кодировки на основе латиницы. Например, ISO 8859-1 — это так называемая «западноевропейская кодировка», которая может быть использована для адекватного кодирования большинства западноевропейских языков. Опять же, есть несколько способов записи даже названия этого стандарта. К сожалению.
Два специальных локали заслуживают особого упоминания: «C» и «POSIX». В настоящее время они фактически являются одной и той же локалью: разница в основном заключается в том, что первая определена стандартом C, а вторая — стандартом POSIX. Они определяют локаль по умолчанию, в которой каждая программа запускается при отсутствии информации о локали в среде. (Если хотите, стандартная локаль по умолчанию). Её языком является (американский) английский, а набор символов — ASCII или, в редких случаях, его надмножество (например, «Многонациональный набор символов DEC (DEC-MCS)»). Предупреждение. Локаль C, предоставленная некоторыми поставщиками, может фактически не совпадать с тем, что называется в стандарте C. Поэтому будьте осторожны.
ПРИМЕЧАНИЕ: Не все системы имеют локаль «POSIX» (не все системы соответствуют POSIX), поэтому используйте «C», когда вам необходимо явно указать эту локаль по умолчанию.
ПРОБЛЕМЫ С ЛОКАЛЬЮ
При запуске Perl вы можете столкнуться с следующим сообщением об ошибке:
perl: warning: Setting locale failed.
perl: warning: Please check that your locale settings:
LC_ALL = "En_US",
LANG = (unset)
are supported and installed on your system.
perl: warning: Falling back to the standard locale ("C"). Это означает, что в ваших настройках локали LC_ALL было установлено значение «En_US», а LANG существует, но не имеет значения. Perl попытался вам поверить, но не смог. Вместо этого Perl отказался и перешёл на локаль «C», локаль по умолчанию, которая должна работать независимо от чего угодно. (В Windows сначала пытается перейти на системную локаль по умолчанию). Это обычно означает, что настройки локали были неверными, они упоминают локали, о которых ваша система никогда не слышала, или в установке локали на вашей системе есть проблемы (например, некоторые системные файлы повреждены или отсутствуют). Существуют быстрые и временные исправления этих проблем, а также более тщательные и долговременные решения.
Проверка неисправных локалей
Если вы собираете Perl из исходных кодов, файл тестового набора Perl lib/locale.t можно использовать для проверки локалей на вашей системе. Установка переменной среды PERL_DEBUG_FULL_TEST в значение 1 заставит его выводить подробные результаты. Например, в Linux вы можете сказать
PERL_DEBUG_FULL_TEST=1 ./perl -T -Ilib lib/locale.t > locale.log 2>&1 Помимо многих других тестов, он будет проверять каждую найденную на вашей системе локаль на соответствие стандарту POSIX. Если в какой-либо из них есть ошибки, в конце вывода будет представлен сводный отчёт, в котором указано, какие локали прошли все тесты, а какие нет и почему.
Временное исправление проблем с локалью
Два самых быстрых исправления — либо заставить Perl молчать о любых несоответствиях в локали, либо запустить Perl в локали по умолчанию «C».
Молчание Perl о проблемах с локалью можно обеспечить, установив переменную среды PERL_BADLANG в значение «0» или «». Этот метод фактически просто замалчивает проблему: вы говорите Perl замолчать, даже если Perl видит, что что-то не так. Не удивляйтесь, если впоследствии что-то зависящее от локали будет работать некорректно.
Perl можно запустить в локали «C», установив переменную среды LC_ALL в значение «C». Этот метод, возможно, немного более цивилизованный, чем подход PERL_BADLANG, но установка LC_ALL (или других переменных локали) может повлиять и на другие программы, а не только на Perl. В частности, внешние программы, запущенные изнутри Perl, увидят эти изменения. Если вы сделаете новые настройки постоянными (читайте дальше), все программы, которые вы запустите, увидят изменения. Смотрите "СРЕДА" для полного списка соответствующих переменных среды и "ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ" для их эффектов в Perl. Эффекты в других программах легко выводимы. Например, переменная LC_COLLATE может повлиять на вашу программу sort (или как называется программа, которая сортирует «записи» в алфавитном порядке на вашей системе).
Вы можете проверить изменения этих переменных временно, и если новые настройки кажутся полезными, поместите эти настройки в файлы запуска вашей оболочки. Обратитесь к вашей локальной документации для получения точных деталей. Для оболочек типа Bourne (sh, ksh, bash, zsh):
LC_ALL=en_US.ISO8859-1
export LC_ALL Предполагается, что мы увидели локаль «en_US.ISO8859-1» с помощью рассмотренных выше команд. Мы решили попробовать её вместо вышеупомянутой неисправной локали «En_US» — и в оболочках типа Csh (csh, tcsh)
setenv LC_ALL en_US.ISO8859-1 или если у вас есть приложение «env», вы можете сделать (в любой оболочке)
env LC_ALL=en_US.ISO8859-1 perl ... Если вы не знаете, какая у вас оболочка, обратитесь к своему локальному отделу поддержки или аналогичной службе.
Постоянное исправление проблем с локалью
Более медленные, но лучшие исправления — это те, когда вы можете сами исправить неверную конфигурацию своих переменных среды. Неправильная конфигурация локалей всей системы обычно требует помощи вашего системного администратора.
Сначала см. предыдущие части документа об "Поиске локалей". Это расскажет, какие локали действительно поддерживаются — и, что более важно, установлены — на вашей системе. В нашем примере сообщения об ошибке переменные среды, влияющие на локаль, перечислены в порядке убывания важности (и не заданные переменные не имеют значения). Поэтому установка LC_ALL в «En_US» должна была стать плохим выбором, как показано в сообщении об ошибке. Сначала попробуйте исправить настройки локали, перечисленные первыми.
Во-вторых, если при использовании перечисленных команд вы видите что-то точно (сопоставления по префиксу не учитываются, а регистр обычно учитывается) вроде «En_US» без кавычек, то всё в порядке, потому что вы используете имя локали, которое должно быть установлено и доступно в вашей системе. В этом случае см. "Постоянное выправление конфигурации локалей вашей системы".
Постоянное выправление конфигурации локалей вашей системы
Это происходит, когда вы видите что-то вроде:
perl: warning: Please check that your locale settings:
LC_ALL = "En_US",
LANG = (unset)
are supported and installed on your system. но не видите «En_US», перечисленного вышеупомянутыми командами. Вы можете увидеть что-то вроде «en_US.ISO8859-1», но это не то же самое. В этом случае попробуйте запустить программу с локалью, которую вы можете перечислить и которая каким-то образом соответствует тому, что вы пытались использовать. Правила сопоставления имён локалей немного расплывчаты, потому что стандартизация в этой области слабая. См. снова раздел "Поиск локалей" об общих правилах.
Выправление конфигурации локалей системы
Обратитесь к системному администратору (желательно к вашему) и сообщите точное сообщение об ошибке, которое вы получаете, и попросите его прочитать эту документацию, которую вы сейчас читаете. Он должен уметь проверить, нет ли проблем с конфигурацией локалей системы. К сожалению, раздел "Поиск локалей" немного расплывчато описывает точные команды и места, поскольку эти вещи не очень стандартизированы.
Функция localeconv
Функция POSIX::localeconv() позволяет получить сведения о форматировании чисел, зависящем от локали, которые заданы текущими базовыми LC_NUMERIC и LC_MONETARY локалями (независимо от того, вызвана ли она в рамках области use locale или нет). (Если вам нужно только имя текущей локали для определённой категории, используйте POSIX::setlocale() с одним параметром — см. "Функция setlocale".)
use POSIX qw(locale_h);
# Get a reference to a hash of locale-dependent info
$locale_values = localeconv();
# Output sorted list of the values
for (sort keys %$locale_values) {
printf "%-20s = %s\n", $_, $locale_values->{$_}
} localeconv() не принимает аргументов и возвращает ссылку на хеш. Ключи этого хеша — это имена переменных для форматирования, такие как decimal_point и thousands_sep. Значения — соответствующие, э-э, значения. См. "localeconv" в POSIX для более подробного примера, перечисляющего категории, которые может предоставить реализация; некоторые предоставляют больше, а другие — меньше. Вам не нужен явный use locale, потому что localeconv() всегда учитывает текущую локаль.
Вот простая программа-пример, которая преобразует параметры командной строки в правильно отформатированные целые числа в соответствии с текущей локалью:
use POSIX qw(locale_h);
# Get some of locale's numeric formatting parameters
my ($thousands_sep, $grouping) =
@{localeconv()}{'thousands_sep', 'grouping'};
# Apply defaults if values are missing
$thousands_sep = ',' unless $thousands_sep;
# grouping and mon_grouping are packed lists
# of small integers (characters) telling the
# grouping (thousand_seps and mon_thousand_seps
# being the group dividers) of numbers and
# monetary quantities. The integers' meanings:
# 255 means no more grouping, 0 means repeat
# the previous grouping, 1-254 means use that
# as the current grouping. Grouping goes from
# right to left (low to high digits). In the
# below we cheat slightly by never using anything
# else than the first grouping (whatever that is).
if ($grouping) {
@grouping = unpack("C*", $grouping);
} else {
@grouping = (3);
}
# Format command line params for current locale
for (@ARGV) {
$_ = int; # Chop non-integer part
1 while
s/(\d)(\d{$grouping[0]}($|$thousands_sep))/$1$thousands_sep$2/;
print "$_";
}
print "\n"; Обратите внимание, что если на платформе недоступны и/или не включены LC_NUMERIC и LC_MONETARY, соответствующие элементы хеша будут отсутствовать.
I18N::Langinfo
Ещё один интерфейс для запроса информации, зависящей от локали, — это функция I18N::Langinfo::langinfo().
В следующем примере будет импортирована функция langinfo() и три константы, которые будут использоваться в качестве аргументов для langinfo(): константа для сокращённого первого дня недели (нумерация начинается с воскресенья = 1) и две дополнительные константы для утвердительных и отрицательных ответов на вопрос «да/нет» в текущей локали.
use I18N::Langinfo qw(langinfo ABDAY_1 YESSTR NOSTR);
my ($abday_1, $yesstr, $nostr)
= map { langinfo } qw(ABDAY_1 YESSTR NOSTR);
print "$abday_1? [$yesstr/$nostr] "; Другими словами, в локали «C» (или английском) выше, вероятно, будет напечатано что-то вроде:
Sun? [yes/no] См. I18N::Langinfo для получения дополнительной информации.
КАТЕГОРИИ ЛОКАЛЕЙ
В следующих разделах описываются основные категории локалей. Помимо этого, некоторые комбинационные категории позволяют манипулировать сразу несколькими базовыми категориями. См. "СРЕДА" для обсуждения этих вопросов.
Категория LC_COLLATE: Сортировка: Сравнение и сортировка текста
В контексте формы use locale, которая включает сортировку, Perl обращается к переменной окружения LC_COLLATE для определения представлений приложения о сортировке (упорядочении) символов. Например, «b» следует за «a» в латинских алфавитах, но где стоят «á» и «å»? И, хотя «цвет» следует за «шоколад» по-английски, а как по-испански?
Следующие сортировки имеют смысл, и вы можете столкнуться с любой из них, если "use locale".
A B C D E a b c d e
A a B b C c D d E e
a A b B c C d D e E
a b c d e A B C D E Вот фрагмент кода, который показывает, какие символы являются "словами" в текущей локали, в порядке этой локали:
use locale;
print +(sort grep /\w/, map { chr } 0..255), "\n"; Сравните это с символами, которые вы видите, и их порядком, если вы явно укажете, что локаль должна быть проигнорирована:
no locale;
print +(sort grep /\w/, map { chr } 0..255), "\n"; Эта машинная сортировка (которую вы получаете, если use locale не появилась ранее в том же блоке) должна использоваться для сортировки сырых двоичных данных, в то время как зависимая от локали сортировка первого примера полезна для обычного текста.
Как отмечалось в "ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ", cmp сравнивает в соответствии с текущей локалью сортировки, когда use locale активна, но возвращается к посимвольному сравнению для строк, которые локаль считает равными. Вы можете использовать POSIX::strcoll(), если не хотите этого возврата:
use POSIX qw(strcoll);
$equal_in_locale =
!strcoll("space and case ignored", "SpaceAndCaseIgnored"); $equal_in_locale будет истинным, если локаль сортировки определяет упорядочение, подобное словарю, которое полностью игнорирует пробелы и преобразует регистр.
Perl использует функции сортировки платформенной библиотеки C strcoll() и strxfrm(). Это означает, что вы получаете то, что они дают. На некоторых платформах эти функции хорошо работают с локалями UTF-8, предоставляя разумную по умолчанию сортировку для кодовых точек, важных для этой локали. (И если они не работают хорошо, проблема может заключаться только в том, что определение локали неполно, поэтому её можно исправить, используя лучшее определение файла. Определения Юникода (см. "Свободно доступные определения локалей") обеспечивают разумные определения сортировки локалей UTF-8.) Начиная с Perl версии 5.26, использование Perl этих функций стало более бесшовным. Это может быть достаточно для ваших нужд. Для большего контроля и для того, чтобы убедиться, что строки, содержащие любой кодовый символ (не только те, которые важны в локали), сортируются правильно, рекомендуется использовать модуль Unicode::Collate.
В локалях, не являющихся UTF-8 (следовательно, однобайтовые), кодовые точки выше 0xFF технически неверны. Но если они присутствуют, опять же, начиная с версии 5.26, они будут сортироваться на той же позиции, что и самая высокая действительная кодовая точка. Это обычно даёт хорошие результаты, но порядок сортировки может быть искажён, если действительная кодовая точка получает специальное обращение, когда она образует определённые последовательности с другими символами, как определено в локали. Когда две строки сортируются одинаково, порядок кодовых точек используется в качестве критерия разрыва ничьей.
Если Perl обнаруживает проблемы с порядком сортировки локали, он переходит к использованию правил сортировки без учёта локали для этой локали.
Если у вас есть одна строка, которую вы хотите проверить на «равенство в локали» относительно нескольких других, вы можете подумать, что сможете немного повысить эффективность, используя POSIX::strxfrm() в сочетании с eq:
use POSIX qw(strxfrm);
$xfrm_string = strxfrm("Mixed-case string");
print "locale collation ignores spaces\n"
if $xfrm_string eq strxfrm("Mixed-casestring");
print "locale collation ignores hyphens\n"
if $xfrm_string eq strxfrm("Mixedcase string");
print "locale collation ignores case\n"
if $xfrm_string eq strxfrm("mixed-case string"); strxfrm() берёт строку и преобразует её в преобразованную строку для использования в посимвольном сравнении с другими преобразованными строками во время сортировки. «Под капотом», операторы сравнения Perl, зависящие от локали, вызывают strxfrm() для обоих операндов, а затем выполняют посимвольное сравнение преобразованных строк. Вызвав strxfrm() явно и используя сравнение, не зависящее от локали, пример пытается сэкономить несколько преобразований. Но на самом деле, это ничего не экономит: магия Perl (см. "Magic Variables" в perlguts) создаёт преобразованную версию строки в первый раз, когда она нужна в сравнении, а затем сохраняет эту версию на случай, если она понадобится снова. Пример, переписанный простым способом с cmp, выполняется примерно с той же скоростью. Он также справляется с нулевыми символами, встроенными в строки; если вы вызываете strxfrm() непосредственно, он рассматривает первый найденный ноль как терминатор. Не ожидайте, что преобразованные строки, которые он генерирует, будут переносимы между системами — или даже между версиями вашей операционной системы. Короче говоря, не вызывайте strxfrm() напрямую: позвольте Perl сделать это за вас.
Примечание: use locale не показано в некоторых из этих примеров, потому что оно не требуется: strcoll() и strxfrm() являются функциями POSIX, которые используют стандартные функции, предоставляемые системой libc, которые всегда следуют текущей LC_COLLATE локали.
Категория LC_CTYPE: Типы символов
В контексте формы use locale, которая включает LC_CTYPE, Perl подчиняется настройке локали LC_CTYPE. Это определяет представление приложения о том, какие символы являются буквенными, числовыми, знаками препинания и т. д. Это влияет на метанотацию регулярных выражений Perl \w, которая обозначает буквенно-цифровые символы — то есть буквенные, числовые и символы нижнего подчёркивания, собственные для платформы. (См. perlre для получения дополнительной информации о регулярных выражениях.) Благодаря LC_CTYPE, в зависимости от вашей настройки локали, символы, такие как «æ», «ð», «ß» и «ø», могут пониматься как \w символы. Это также влияет на такие вещи, как \s, \D, и классы символов POSIX, такие как [[:graph:]]. (См. perlrecharclass для получения дополнительной информации обо всех этих вещах.)
Локаль LC_CTYPE также предоставляет карту, используемую для транслитерации символов между строчными и прописными. Это влияет на функции преобразования регистра — fc(), lc(), lcfirst(), uc(), и ucfirst(); преобразование регистра с помощью \F, \l, \L, \u, или \U в строках с двойными кавычками и s/// заменах; и поиск совпадений шаблонов регулярных выражений без учёта регистра с использованием модификатора i.
Начиная с версии v5.20, Perl поддерживает локали UTF-8 для LC_CTYPE, но в противном случае Perl поддерживает только локали с однобайтовыми символами, такие как ISO 8859. Это означает, что локали с широким набором символов, например, для азиатских языков, не поддерживаются должным образом. Использование таких локалей может привести к ошибке core dump. Если платформа позволяет Perl определять такую локаль, начиная с Perl v5.22, Perl будет выдавать предупреждение, по умолчанию включенное, используя категорию предупреждений locale, всякий раз, когда такая локаль активируется. Поддержка локали UTF-8 фактически является супермножеством локалей POSIX, потому что она реализует полное поведение Unicode, как будто никакая LC_CTYPE локаль не активна (за исключением помечания; см. "БЕЗОПАСНОСТЬ"). Локали POSIX, даже UTF-8, не обладают определенными концепциями Unicode, такими как идея, что изменение регистра символа может расшириться до нескольких символов. Perl в локали UTF-8 предоставит вам это расширение. До версии v5.20 Perl на некоторых платформах обрабатывал локаль UTF-8 как локаль ISO 8859-1 с некоторыми ограничениями, а на других платформах — как локаль «C». Для выпусков v5.16 и v5.18, use locale 'not_characters можно было использовать в качестве обходного решения для этого (см. "Unicode и UTF-8").
Обратите внимание, что некоторые вещи не зависят от текущей локали. Любой буквенный символ — это родной символ для данной платформы. Следовательно, 'A' означает символ с кодом 65 в ASCII, и 193 в EBCDIC. Это может или не может быть 'A' в текущей локали, если в этой локали вообще есть 'A'. Аналогично, все последовательности экранирования для определенных символов, \n например, всегда означают родной для платформы. Это означает, например, что \N в регулярных выражениях (любой символ, кроме новой строки) работает с набором символов платформы.
Начиная с версии v5.22, Perl по умолчанию будет выдавать предупреждение при переключении на локаль, которая переопределяет любой печатаемый символ ASCII (плюс \t и \n) в класс, отличный от ожидаемого. Это, скорее всего, произойдет в современных локалях только на платформах EBCDIC, где, например, локаль CCSID 0037 на машине CCSID 1047 перемещает "[", но это может произойти на платформах ASCII с локалями ISO 646 и другими 7-битовыми локалями, которые в основном устарели. Вещи все еще могут работать, в зависимости от того, какие функции Perl используются программой. Например, в примере выше, где "|" становится \w, и нет регулярных выражений, где это имеет значение, программа может по-прежнему работать правильно. Предупреждение перечисляет все символы, которые, по его мнению, могут быть неблагоприятно затронуты.
Примечание: Некорректное или злонамеренное LC_CTYPE определение локали может привести к тому, что явно недопустимые символы будут считаться буквенно-цифровыми в вашем приложении. Для строгого соответствия (обычным) буквам и цифрам ASCII — например, в командных строках — приложения, учитывающие локаль, должны использовать \w с модификатором регулярного выражения /a. См. "БЕЗОПАСНОСТЬ".
Категория LC_NUMERIC: Форматирование чисел
После вызова POSIX::setlocale() и в рамках use locale формы, включающей числа, Perl подчиняется информации локали LC_NUMERIC, которая управляет представлением приложения о том, как числа должны форматироваться для лучшей читаемости человеком. В большинстве реализаций единственным эффектом является изменение символа, используемого для десятичной точки — возможно, с «.» на «,». Функции не осознают таких тонкостей, как разделение тысяч и т. д. (См. "Функция localeconv", если вас интересуют эти вещи.)
use POSIX qw(strtod setlocale LC_NUMERIC);
use locale;
setlocale LC_NUMERIC, "";
$n = 5/2; # Assign numeric 2.5 to $n
$a = " $n"; # Locale-dependent conversion to string
print "half five is $n\n"; # Locale-dependent output
printf "half five is %g\n", $n; # Locale-dependent output
print "DECIMAL POINT IS COMMA\n"
if $n == (strtod("2,5"))[0]; # Locale-dependent conversion См. также I18N::Langinfo и RADIXCHAR.
Категория LC_MONETARY: Форматирование денежных сумм
Стандарт C определяет категорию LC_MONETARY, но не функцию, которая зависит от ее содержимого. (Те, кто знаком с комитетами по стандартам, признают, что рабочая группа решила не затрагивать этот вопрос.) В результате Perl по существу не обращает на него внимания. Если вы действительно хотите использовать LC_MONETARY, вы можете запросить ее содержимое — см. "Функцию localeconv" — и использовать полученную информацию в собственном форматировании валютных сумм вашего приложения. Однако, вы можете обнаружить, что эта информация, хоть и обширная и сложная, всё же не совсем соответствует вашим требованиям: форматирование валюты — сложная задача.
См. также I18N::Langinfo и CRNCYSTR.
Категория LC_TIME: Представление времени
Выходные данные, созданные POSIX::strftime(), которые строят отформатированную удобочитаемую строку даты/времени, зависят от текущей локали LC_TIME. Таким образом, во французской локали вывод, создаваемый элементом формата %B (полное название месяца) для первого месяца года, будет «janvier». Вот как получить список полных названий месяцев в текущей локали:
use POSIX qw(strftime);
for (0..11) {
$long_month_name[$_] =
strftime("%B", 0, 0, 0, 1, $_, 96);
} Примечание: use locale в этом примере не требуется: strftime() — функция POSIX, использующая стандартную системную функцию libc, которая всегда подчиняется текущей локали LC_TIME.
См. также I18N::Langinfo и ABDAY_1..ABDAY_7, DAY_1..DAY_7, ABMON_1..ABMON_12, и ABMON_1..ABMON_12.
Другие категории
Остальные категории локалей в настоящее время не используются самим Perl. Но обратите внимание, что другие элементы, с которыми взаимодействует Perl, могут использовать их, включая расширения, не входящие в стандартное распределение Perl, а также операционную систему и ее утилиты. Обратите особое внимание на то, что строковое значение $! и сообщения об ошибках, выдаваемые внешними утилитами, могут быть изменены LC_MESSAGES. Если вам нужны переносимые коды ошибок, используйте %!. См. Errno.
БЕЗОПАСНОСТЬ
Хотя основное обсуждение проблем безопасности Perl можно найти в perlsec, обсуждение обработки локалей Perl будет неполным, если оно не привлечет ваше внимание к проблемам безопасности, зависящим от локали. Локали — особенно на системах, которые позволяют пользователям без привилегий создавать свои собственные локали — ненадёжны. Злонамеренная (или просто некорректная) локаль может привести к тому, что приложение, учитывающее локаль, даст неожиданные результаты. Вот несколько возможных вариантов:
-
Проверки регулярных выражений на безопасные имена файлов или адреса электронной почты с использованием
\wмогут быть обмануты локальLC_CTYPE, которая утверждает, что такие символы, как">"и"|"являются буквенно-цифровыми. -
Интерполяция строк с преобразованием регистра, как в, скажем,
$dest = "C:\U$name.$ext", может привести к опасным результатам, если активна ложнаяLC_CTYPEтаблица преобразования регистра. -
Хитрая
LC_COLLATEлокаль может привести к тому, что имена студентов с оценкой «D» будут появляться раньше тех, у кого оценка «A». -
Приложения, которые утруждают себя использованием информации в
LC_MONETARY, могут форматировать дебетовые операции так, как будто они являются кредитовыми, и наоборот, если эта локаль была взломана. Или оно может производить платежи в долларах США вместо гонконгских долларов. -
Дата и названия дней в датах, отформатированных
strftime(), могут быть изменены злонамеренным пользователем, способным изменить локальLC_DATE. («Посмотрите, — говорит он, — у меня не было входа в здание в воскресенье».)
Эти опасности не являются специфичными для системы локалей: любой аспект среды приложения, который можно изменить злонамеренно, представляет аналогичные проблемы. Аналогично, они не специфичны для Perl: любой язык программирования, который позволяет создавать программы, учитывающие их среду, подвергает вас этим проблемам.
Perl не может защитить вас от всех возможных случаев, показанных в примерах — вашей бдительности нет замены — но, когда use locale активна, Perl использует механизм помечания (см. perlsec) для маркировки результатов строк, которые становятся зависящими от локали и которые могут быть ненадежными в результате.
-
Операторы сравнения (
lt,le,ge,gtиcmp):Результат скалярного значения true/false (или меньше/равно/больше) никогда не загрязняется.
-
Интерполяция преобразования регистра (с
\l,\L,\u,\U, или\F)Строка результата, содержащая интерполированный материал, загрязняется, если используется форма
use locale, которая включаетLC_CTYPE. -
Оператор соответствия (
m//):Скалярный результат true/false никогда не загрязняется.
Все подмаски, полученные как результат контекста списка или как
$1и т. д., загрязняются, если используется формаuse locale, которая включаетLC_CTYPE, и регулярное выражение подмаски содержит конструкцию, зависящую от локали. Эти конструкции включают\w(для сопоставления буквенно-цифрового символа),\W(небуквенно-цифрового символа),\bи\B(границы слов и неграницы, которые зависят от того, что\wи\Wсоответствуют),\s(символ пробела),\S(непробельный символ),\dи\D(цифры и нецифры), а также POSIX-классы символов, такие как[:alpha:](см. "POSIX Character Classes" в perlrecharclass).Загрязнение также вероятно, если шаблон должен быть сопоставлен без учета регистра (через
/i). Исключением является случай, когда все кодовые точки, которые должны быть сопоставлены таким образом, находятся выше 255 и не имеют сгибов по правилам Юникода ниже 256. Загрязнение для них не выполняется, поскольку Perl использует только правила Юникода для таких кодовых точек, а эти правила одинаковы независимо от текущей локали.Переменные, соответствующие шаблону,
$&,$`(префикс),$'(постфикс) и$+(последнее соответствие) также загрязняются. -
Оператор подстановки (
s///):Обладает тем же поведением, что и оператор соответствия. Кроме того, левый операнд
=~загрязняется, когда используется формаuse locale, которая включаетLC_CTYPE, если он изменяется в результате подстановки, основанной на сопоставлении с регулярным выражением, вовлекая в себя любые из упомянутых в предыдущем пункте элементов, или преобразования регистра, таких как\l,\L,\u,\Uили\F. -
Функции форматирования вывода (
printf()иwrite()):Результаты никогда не загрязняются, иначе даже вывод из print, например
print(1/7), должен быть загрязнено, еслиuse localeактивен. -
Функции преобразования регистра (
lc(),lcfirst(),uc(),ucfirst()):Результаты загрязняются, если используется форма
use locale, которая включаетLC_CTYPE. -
Функции POSIX, зависящие от локали (
localeconv(),strcoll(),strftime(),strxfrm()):Результаты никогда не загрязняются.
Три примера иллюстрируют загрязнение, зависящее от локали. Первая программа, которая игнорирует свою локаль, не запустится: значение, взятое непосредственно из командной строки, не может быть использовано для именования выходного файла при включенных проверках загрязнения.
#/usr/local/bin/perl -T
# Run with taint checking
# Command line sanity check omitted...
$tainted_output_file = shift;
open(F, ">$tainted_output_file")
or warn "Open of $tainted_output_file failed: $!\n"; Программа может быть запущена, «отмыв» загрязненное значение через регулярное выражение: во втором примере — который по-прежнему игнорирует информацию о локали — программа запускается, создавая файл с именем в командной строке, если это возможно.
#/usr/local/bin/perl -T
$tainted_output_file = shift;
$tainted_output_file =~ m%[\w/]+%;
$untainted_output_file = $&;
open(F, ">$untainted_output_file")
or warn "Open of $untainted_output_file failed: $!\n"; Сравните это с аналогичной, но учитывающей локаль программой:
#/usr/local/bin/perl -T
$tainted_output_file = shift;
use locale;
$tainted_output_file =~ m%[\w/]+%;
$localized_output_file = $&;
open(F, ">$localized_output_file")
or warn "Open of $localized_output_file failed: $!\n"; Эта третья программа не запускается, потому что $& загрязнено: это результат соответствия, включающего \w, в то время как use locale включена.
Окружение
- PERL_SKIP_LOCALE_INIT
-
Эта переменная среды, доступная начиная с Perl v5.20, если установлена (любое значение), сообщает Perl, что не следует использовать остальные переменные среды для инициализации. Вместо этого Perl использует текущие настройки локали. Это особенно полезно во встроенных средах, см. "Использование встроенного Perl с POSIX-локальностью" в perlembed.
- PERL_BADLANG
-
Строка, которая может подавить предупреждение Perl о неудачных настройках локали при запуске. Ошибка может произойти, если поддержка локали в операционной системе каким-либо образом отсутствует (нерабочая) — или если вы неправильно ввели имя локали при настройке окружения. Если эта переменная среды отсутствует или имеет значение, отличное от "0" или "", Perl будет жаловаться на ошибки настроек локали.
ПРИМЕЧАНИЕ:
PERL_BADLANGпредоставляет только способ скрыть сообщение об ошибке. Сообщение указывает на какую-то проблему в поддержке локали вашей системы, и вы должны исследовать, в чём проблема.
Следующие переменные среды не специфичны для Perl: Они являются частью стандартизированного (ISO C, XPG4, POSIX 1.c) setlocale() метода управления мнением приложения о данных. Windows не POSIX, но Perl позаботился о том, чтобы это работало описанным образом. Если локаль, заданная переменной среды, недействительна, Perl пытается использовать следующую локаль с более низким приоритетом. Если ни одна из них недействительна, в Windows используется системная локаль по умолчанию. Если всё остальное не сработает, локаль "C" используется. Если даже это не сработает, что-то сильно сломано, но Perl пытается продолжить работу с имеющимися настройками локали.
LC_ALL-
LC_ALL— переменная среды локали "переопределение всех". Если она установлена, она переопределяет все остальные переменные среды локали. LANGUAGE-
ПРИМЕЧАНИЕ:
LANGUAGE— расширение GNU, оно влияет только в случае использования GNU libc. Это относится, например, к Linux. Если вы используете "коммерческие" Unix-системы, вы, скорее всего, не используете GNU libc, и можете игнорироватьLANGUAGE.Однако, если вы используете
LANGUAGE, он влияет на язык информационных, предупреждающих и ошибочных сообщений, выводимых командами (другими словами, он какLC_MESSAGES), но имеет более высокий приоритет, чемLC_ALL. Более того, это не единственное значение, а "путь" (список, разделённый двоеточием), языков (не локалей). Для получения дополнительной информации см. документацию библиотеки GNUgettext. LC_CTYPE-
В отсутствие
LC_ALL,LC_CTYPEвыбирает локаль типа символов. В отсутствие какLC_ALL, так иLC_CTYPE,LANGвыбирает локаль типа символов. LC_COLLATE-
В отсутствие
LC_ALL,LC_COLLATEвыбирает локаль сортировки. В отсутствие какLC_ALL, так иLC_COLLATE,LANGвыбирает локаль сортировки. LC_MONETARY-
В отсутствие
LC_ALL,LC_MONETARYвыбирает локаль денежного форматирования. В отсутствие какLC_ALL, так иLC_MONETARY,LANGвыбирает локаль денежного форматирования. LC_NUMERIC-
В отсутствие
LC_ALL,LC_NUMERICвыбирает локаль числового формата. В отсутствие какLC_ALL, так иLC_NUMERIC,LANGвыбирает числовой формат. LC_TIME-
В отсутствие
LC_ALL,LC_TIMEвыбирает локаль форматирования даты и времени. В отсутствие какLC_ALL, так иLC_TIME,LANGвыбирает локаль форматирования даты и времени. LANG-
LANG— переменная среды локали "catch-all". Если она установлена, она используется в последнюю очередь после общейLC_ALLи специфичной по категориямLC_foo.
Примеры
LC_NUMERIC контролирует числовой вывод:
use locale;
use POSIX qw(locale_h); # Imports setlocale() and the LC_ constants.
setlocale(LC_NUMERIC, "fr_FR") or die "Pardon";
printf "%g\n", 1.23; # If the "fr_FR" succeeded, probably shows 1,23. а также то, как строки анализируются функцией POSIX::strtod() как числа:
use locale;
use POSIX qw(locale_h strtod);
setlocale(LC_NUMERIC, "de_DE") or die "Entschuldigung";
my $x = strtod("2,34") + 5;
print $x, "\n"; # Probably shows 7,34. ПРИМЕЧАНИЯ
Строка eval и LC_NUMERIC
Функция eval анализирует выражение как стандартный Perl. Следовательно, она ожидает, что десятичная точка будет точкой. Если LC_NUMERIC настроена так, чтобы это была запятая, анализ будет затруднён, возможно, без предупреждений.
use locale;
use POSIX qw(locale_h);
setlocale(LC_NUMERIC, "fr_FR") or die "Pardon";
my $a = 1.2;
print eval "$a + 1.5";
print "\n"; выводит 13,5. Это связано с тем, что в этой локали запятая — символ десятичной точки. eval таким образом расширяется до:
eval "1,2 + 1.5" и результат не тот, который вы, вероятно, ожидали. Предупреждения не генерируются. Если вы выполняете строковые eval внутри области use locale, вам следует вместо этого изменить строку eval на что-нибудь вроде:
print eval "no locale; $a + 1.5"; Это выводит 2.7.
Вы также можете исключить LC_NUMERIC, если вам это не нужно:
use locale ':!numeric'; Обратная совместимость
Версии Perl до 5.004 в основном игнорировали информацию о локали, обычно ведя себя так, как будто локаль, похожая на "C", всегда действовала, даже если окружение программы предполагало иное (см. "Функция setlocale"). По умолчанию Perl по-прежнему ведёт себя таким образом для обеспечения обратной совместимости. Если вы хотите, чтобы приложение Perl обращало внимание на информацию о локали, вы обязательно должны использовать псевдоним use locale (см. "Псевдоним "use locale"") или, в маловероятном случае, если вы хотите сделать это только для сопоставления шаблонов, модификатор регулярного выражения /l (см. "Модификаторы набора символов" в perlre), чтобы указать это.
Версии Perl от 5.002 до 5.003 использовали информацию LC_CTYPE, если она была доступна; то есть, \w понимал, какие буквы соответствуют переменным среды локали. Проблема заключалась в том, что пользователь не мог контролировать эту функцию: если C-библиотека поддерживала локали, Perl использовал их.
I18N: устаревший Collate
В версиях Perl до 5.004 сортировка с учетом локали была возможна с использованием модуля библиотеки I18N::Collate. Этот модуль сейчас устарел и следует избегать в новых приложениях. Функциональность LC_COLLATE теперь интегрирована в ядро языка Perl: вы можете использовать данные скаляров, специфичные для локали, совершенно нормально с помощью use locale, поэтому больше нет необходимости работать со ссылками на скаляры I18N::Collate.
Влияние скорости сортировки и использования памяти
Сравнение и сортировка по локали обычно медленнее, чем сортировка по умолчанию; было замечено замедление в два-четыре раза. Это также потребует больше памяти: после того, как переменная скаляра Perl участвовала в любой операции сравнения строк или сортировки, подчиняющейся правилам сортировки локали, она будет занимать в 3-15 раз больше памяти, чем раньше. (Точный множитель зависит от содержимого строки, операционной системы и локали.) Эти недостатки диктуются скорее реализацией операционной системы системы локали, чем Perl.
Свободно доступные определения локали
Проект Unicode CLDR извлекает часть POSIX многих своих локалей, доступных по адресу
http://unicode.org/Public/cldr/2.0.1/ (Более новые версии CLDR требуют, чтобы вы вычисляли данные POSIX самостоятельно. См. http://unicode.org/Public/cldr/latest/.)
Существует большая коллекция определений локали по адресу:
http://std.dkuug.dk/i18n/WG15-collection/locales/ Вы должны понимать, что она не поддерживается и не претендует на пригодность для каких-либо целей. Если ваша система позволяет устанавливать произвольные локали, вы можете найти определения полезными как они есть, или в качестве основы для разработки своих собственных локалей.
I18n и l10n
«Международная локализация» часто сокращается как i18n, потому что ее первые и последние буквы разделены восемнадцатью другими. (Вы можете догадаться, почему внутренний ... внутренняя ... i18n склонна к сокращению.) Точно так же «локализация» часто сокращается до l10n.
Несовершенный стандарт
Международная локализация, как определено в стандартах C и POSIX, может быть подвергнута критике за неполноту и громоздкость. Они также, как и группы стандартов, имеют тенденцию делить мир на нации, когда мы все знаем, что мир можно так же хорошо разделить на банкиров, байкеров, геймеров и так далее.
Unicode и UTF-8
Поддержка Unicode появилась с версии Perl v5.6 и более полно реализована в версиях v5.8 и более поздних. См. perluniintro.
Начиная с Perl v5.20, в Perl поддерживаются локали UTF-8, за исключением LC_COLLATE, которая поддерживается только частично; поддержка сортировки улучшена в Perl v5.26 до уровня, который может быть достаточным для ваших нужд (см. "Категория LC_COLLATE: Сортировка: Сравнение и сортировка текста").
Если у вас Perl v5.16 или v5.18 и вы не можете обновить, вы можете использовать
use locale ':not_characters'; При использовании этого формата прагмы Perl использует только несимвольные части локалей, например LC_NUMERIC. Perl предполагает, что вы перевели все символы, с которыми он должен работать, в Unicode (на самом деле, в нативный для платформы набор символов (ASCII или EBCDIC) плюс Unicode). Для данных в файлах это удобно сделать, также указав
use open ':locale'; Эта прагма обеспечивает перевод всех входных данных из файлов в Unicode из текущей локали, указанной в среде (см. "СРЕДА"), и перевод всех выходных данных в файлы обратно в локаль. (См. open). На уровне каждого дескриптора файла вы можете вместо этого использовать модуль PerlIO::locale или модуль Encode::Locale, оба доступны из CPAN. Последний модуль также имеет методы для упрощения обработки ARGV и переменных среды, и может использоваться для отдельных строк. Если вам известно, что все ваши локали будут UTF-8, как многие сейчас, вы можете использовать команду -C.
Этот формат прагмы позволяет существенно бесшовную обработку локалей с Unicode. Порядок сортировки будет по порядку кодовых точек Unicode. Unicode::Collate можно использовать для получения сортировки по правилам Unicode.
Все описанные модули и переключатели могут быть использованы в v5.20 с простым use locale, и, если входные локали не UTF-8, вы получите менее идеальное поведение, описанное ниже, которое вы получаете с Perl'ями до v5.16, или при использовании прагмы локали без параметра :not_characters в v5.16 и v5.18. Если вы используете только локали UTF-8 в v5.20 и выше, остальная часть этого раздела для вас неактуальна.
Существует два случая: многобайтовые и однобайтовые локали. Сначала многобайтовые:
Единственная многобайтовая (или широкая) локаль, которую Perl, скорее всего, будет поддерживать, — это UTF-8. Это связано со сложностью реализации, тем фактом, что высококачественные локали UTF-8 теперь публикуются для каждой области мира (http://unicode.org/Public/cldr/2.0.1/ для уже настроенных, но из более ранней версии; http://unicode.org/Public/cldr/latest/ для самых современных, но вы должны сами извлечь информацию POSIX), и что во всех этих случаях вы можете использовать модуль Encode для перевода в/из вашей локали. Таким образом, вам нужно будет сделать что-то из этого, если вы используете одну из этих локалей, таких как Big5 или Shift JIS. Для UTF-8 локалей в Perl'ях (до v5.20), которые не имеют полной поддержки локали UTF-8, они могут работать довольно хорошо (в зависимости от реализации вашей C-библиотеки) просто потому, что и они, и Perl хранят символы, занимающие несколько байт, одинаковым образом. Однако некоторые, если не большинство, реализации C-библиотеки могут не обрабатывать символы в верхней половине диапазона Latin-1 (128 - 255) должным образом в LC_CTYPE. Чтобы проверить, является ли символ определенного типа в рамках локали, Perl использует функции, такие как isalnum(). Ваша C-библиотека может не работать для UTF-8 локалей с этими функциями, работая только с новыми широкими функциями библиотеки, такими как iswalnum(), которые Perl не использует. Эти многобайтовые локали обрабатываются как однобайтовые локали и будут иметь ограничения, описанные ниже. Начиная с Perl v5.22, при обнаружении многобайтовой локали, которую Perl не полностью поддерживает, выводится сообщение об ошибке.
Для однобайтовых локалей Perl, как правило, использует правила локали для кодовых точек, которые могут поместиться в один байт, и правила Unicode для тех, которые не могут (хотя это не применяется равномерно, см. примечание в конце этого раздела). Это предотвращает многие проблемы в локалях, которые не являются UTF-8. Предположим, локаль — ISO8859-7, греческая. Символ в 0xD7 там — большая буква хи. Но в локали ISO8859-1, Latin1, это знак умножения. Класс символов POSIX [[:alpha:]] магическим образом будет соответствовать 0xD7 в греческой локали, но не в латинской.
Однако есть места, где это терпит неудачу. Определенные конструкции Perl предназначены только для Unicode, такие как \p{Alpha}. Они предполагают, что 0xD7 всегда имеет свое значение Unicode (или эквивалент на платформах EBCDIC). Так как Latin1 является подмножеством Unicode, и 0xD7 — знак умножения как в Latin1, так и в Unicode, \p{Alpha} никогда не будет совпадать с ним независимо от локали. Аналогичная проблема возникает с \N{...}. До v5.20 использование \p{} или \N{} в простом use locale — плохая идея — если только вы не можете гарантировать, что локаль будет ISO8859-1. Используйте классы символов POSIX вместо этого.
Еще одна проблема этого подхода заключается в том, что операции, пересекающие границу один байт/несколько байт, не определены однозначно и поэтому запрещены. (Эта граница находится между кодовыми точками 255/256.) Например, преобразование в нижний регистр LATIN CAPITAL LETTER Y WITH DIAERESIS (U+0178) должно возвращать LATIN SMALL LETTER Y WITH DIAERESIS (U+00FF). Но в греческой локали, например, нет символа в 0xFF, и Perl не знает, что символ в 0xFF на самом деле должен представлять. Поэтому он запрещает операцию. В этом режиме нижний регистр U+0178 — это сам он.
Те же проблемы возникают, если вы включите автоматическое преобразование ваших стандартных файловых дескрипторов в UTF-8, слой по умолчанию open() и @ARGV в не-ISO8859-1, не-UTF-8 локалях (используя команду -C или переменную среды PERL_UNICODE; см. perlrun). Вещи считываются как UTF-8, что обычно предполагает интерпретацию Unicode, но наличие локали заставляет их интерпретироваться вместо этого в этой локали. Например, кодовая точка 0xD7 в входных данных Unicode, которая должна означать знак умножения, не будет интерпретироваться Perl таким образом в греческой локали. Это не проблема при условии, что вы убедитесь, что все локали всегда и только ISO8859-1 или, если у вас нет неисправной C-библиотеки, UTF-8.
Еще одна проблема заключается в том, что этот подход может привести к тому, что две кодовые точки означают один и тот же символ. Таким образом, в греческой локали и U+03A7, и U+00D7 — GREEK CAPITAL LETTER CHI.
Из-за всех этих проблем, начиная с v5.22, Perl будет выдавать предупреждение, если многобайтовая (следовательно, Unicode) кодовая точка используется при наличии однобайтовой локали. (Хотя он не проверяет это, если это приведет к необоснованному замедлению выполнения.)
Локали поставщиков, как известно, содержат ошибки, и Perl сложно тестировать код обработки локалей, поскольку это взаимодействует с кодом, над которым Perl не имеет контроля; поэтому код обработки локалей в Perl также может содержать ошибки. (Однако локали, предоставленные Unicode, должны быть лучше, и есть механизм обратной связи для исправления любых проблем. См. "Свободно доступные определения локали".)
Если у вас Perl v5.16, проблемы, упомянутые выше, исчезают, если вы используете параметр :not_characters для прагмы локали (кроме ошибок поставщика в несимвольных частях). Если у вас нет v5.16, а у вас есть работающие локали, использование их может быть полезным для определенных конкретных целей, если вы помните о проблемах, упомянутых выше. Например, если сортировка для ваших локалей работает, она выполняется быстрее с использованием локалей, чем с Unicode::Collate; и вы получаете доступ к таким вещам, как символ местной валюты и названия месяцев и дней недели. (Но, чтобы подчеркнуть, в v5.16 вы получаете этот доступ без недостатков локалей, используя формат прагмы :not_characters.)
Примечание: Политика использования правил локали для кодовых точек, которые могут поместиться в один байт, и правил Unicode для тех, которые не могут, не применяется повсеместно. До версии 5.12 она была несколько произвольной; в версии 5.12 она применялась довольно последовательно к сопоставлению с регулярными выражениями, за исключением квадратных скобок; в версии 5.14 она была расширена на все соответствия с регулярными выражениями; а в версии 5.16 — на операции преобразования регистра, такие как \L и uc(). Для сортировки в всех выпусках до сих пор вызывается функция системы strxfrm(), и то, что она делает, — это и есть результат. Начиная с версии 5.26, исправлены различные ошибки в том, как Perl использует эту функцию.
ОШИБКИ
Сортировка строк, содержащих вложенные символы NUL
Символы NUL будут сортироваться так же, как и самый низкий управляющий символ сортировки, или как "\001" в маловероятном случае, если в локали вообще нет управляющих символов. В тех случаях, когда строки не содержат этот не-NUL управляющий символ, результаты будут правильными, и во многих локалях этот управляющий символ, каким бы он ни был, встречается редко. Но есть случаи, когда NUL должен сортироваться раньше этого управляющего символа, но этого не происходит. Если две строки сортируются идентично, строка, содержащая NUL будет отсортирована раньше. До версии 5.26 было больше ошибок.
Многопоточность
Код XS или библиотеки на языке C, вызываемые из него и использующие системную функцию setlocale(3) (кроме Windows), вероятно, не будут работать из многопоточного приложения без изменений. См. "Locale-aware XS code" в perlxs.
Модуль XS, зависящий от локали, мог быть написан с предположением, что он никогда не будет вызываться в многопоточной среде, и поэтому использует другие не зависящие от локали конструкции, которые не безопасны для многопоточности. См. "Thread-aware system interfaces" в perlxs.
POSIX не определяет способ получения имени текущей локали для каждого потока. Некоторые системы, такие как Darwin и NetBSD, реализуют функцию querylocale(3) для этого. На системах без неё, таких как Linux, без Windows, есть дополнительные замечания:
-
Встраиваемый Perl должен быть запущен, когда глобальная локаль активна. См. "Using embedded Perl with POSIX locales" в perlembed.
-
Для Perl становится важнее знать обо всех возможных категориях локалей на платформе, даже если они, по-видимому, не используются в вашей программе. Perl знает все локали Linux. Если ваша платформа имеет другие, вы можете отправить электронное письмо по адресу mailto:perlbug@perl.org для включения её в следующий выпуск. Тем временем можно отредактировать исходный код Perl, чтобы он узнал о категории, и затем перекомпилировать его. Поиск примеров, скажем,
LC_PAPERв исходном коде, и использование его в качестве шаблона для добавления пропущенной. -
Возможно, хотя и сложно, вызвать
POSIX::setlocaleс локалью, которую она не распознает как синтаксически корректную, но которая на самом деле корректна в этой системе. Это должно происходить только с встраиваемыми Perl или если вы сами создаёте имя локали.
Неисправные системы
В определённых системах поддержка локали операционной системы неисправна и не может быть использована Perl. Такие недостатки могут и будут приводить к загадочным зависаниям и/или сбросам ядра Perl, когда use locale активен. При столкновении с такой системой, пожалуйста, подробно сообщите об этом по адресу <perlbug@perl.org>, а также свяжитесь с вашим поставщиком: исправления ошибок для этих проблем могут существовать в вашей операционной системе. Иногда такие исправления ошибок называются обновлением операционной системы. Если у вас есть исходный код Perl, включите в электронное письмо по адресу perlbug вывод теста, описанного выше в "Testing for broken locales".
См. также
I18N::Langinfo, perluniintro, perlunicode, open, "localeconv" в POSIX, "setlocale" в POSIX, "strcoll" в POSIX, "strftime" в POSIX, "strtod" в POSIX, "strxfrm" в POSIX.
Для особых случаев, когда Perl встроен в программу на C, см. "Using embedded Perl with POSIX locales" в perlembed.
ИСТОРИЯ
Исходный perli18n.pod Джэркко Хьетаниеми был сильно изменён Домиником Данлопом, при поддержке perl5-porters. Проза была немного переработана Томом Кристиансеном, и теперь поддерживается Perl 5 porters.
© 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.28.3/perllocale