perllocale
СОДЕРЖАНИЕ
- ИМЯ
- ОПИСАНИЕ
- ЧТО ТАКОЕ ЛОКАЛЬ
- ПОДГОТОВКА К ИСПОЛЬЗОВАНИЮ ЛОКАЛЕЙ
- ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ
- Предикат "use locale"
- Функция setlocale
- Многопоточная работа
- Поиск локалей
- ПРОБЛЕМЫ С ЛОКАЛЯМИ
- Проверка на неисправные локали
- Временное исправление проблем с локали
- Постоянное исправление проблем с локали
- Постоянное исправление конфигурации локалей вашей системы
- Исправление конфигурации системной локали
- Функция localeconv
- I18N::Langinfo
- КАТЕГОРИИ ЛОКАЛЕЙ
- БЕЗОПАСНОСТЬ
- СРЕДА
- ПРИМЕЧАНИЯ
- Unicode и UTF-8
- ОШИБКИ
- СМОТРИТЕ ТАКЖЕ
- ИСТОРИЯ
ИМЯ
perllocale — Обработка локалей Perl (международная и локализованная версия)
ОПИСАНИЕ
Вначале был ASCII, «Американский стандартный код обмена информацией», который довольно хорошо работает для американцев с их английским алфавитом и валютой в долларах. Но он работает не так хорошо даже для других англоговорящих, которые могут использовать другие валюты, такие как фунт стерлингов (так как символ этой валюты отсутствует в 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. На самом деле существует два немного разных типа UTF-8 локалей: один для тюркских языков и один для всех остальных.
Начиная с Perl v5.30, Perl обнаруживает тюркские локали по их поведению и бесшовно обрабатывает оба типа; ранее поддерживался только не-тюркский тип. Если ваша система имеет локаль tr_TR.UTF-8, и она не ведет себя как тюркская локаль, Perl будет обрабатывать её как не-тюркскую локаль.
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".
Использование локалей
Директива "use locale"
Начиная с 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() определяется более ранним объявлением формата ("format" в perlfunc), поэтому зависит ли вывод от локали, определяется тем, находится ли
format()в области действия директивыuse locale, а не находится лиwrite()в ней. -
Шаблоны регулярных выражений могут быть скомпилированы с помощью qr// с отложенным фактическим сопоставлением на более поздний этап. Снова, именно то, скомпилировано ли это внутри области действия
use locale, определяет поведение сопоставления, а не то, выполнены ли сопоставления в этой области или нет.
-
-
В области действия директивы
"use locale"; -
-
Все вышеперечисленные операции
-
Объявления форматов ("format" в 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' в пределах своего действия. Эта форма менее полезна в версиях 5.20 и выше и подробно описывается в "Unicode и UTF-8". Однако коротко: она сообщает Perl не использовать символьные части определения локали, то есть категории LC_CTYPE и LC_COLLATE. Вместо этого он будет использовать собственную кодировку символов (расширенную Unicode). При использовании этого параметра вы отвечаете за преобразование внешней кодировки символов в собственную/Unicode (которая уже будет такой, если это одна из все более популярных UTF-8 локалей). Существуют удобные способы сделать это, как описано в "Unicode и UTF-8".
Функция setlocale
ВНИМАНИЕ! До Perl 5.28 или на системах, которые не поддерживают потокобезопасные операции с локалью, НЕ используйте эту функцию в потоке. Локаль изменится во всех других потоках одновременно, и если ваш поток приостановится операционной системой, а другой запустится, этот поток не будет иметь ожидаемой локали. На некоторых платформах может возникнуть ситуация гонки, ведущая к аварийным завершениям (segfaults), если две нити почти одновременно вызывают эту функцию. Это предупреждение не относится к однопоточным сборкам или Perl, где ${^SAFE_LOCALES} существует и не равно нулю; то есть Perl 5.28 и более поздние версии в однопоточном режиме или скомпилированные для потокобезопасной работы с локалью.
Вы можете изменять локали по мере необходимости во время выполнения с помощью функции 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 игнорирует исключённые категории.
Если setlocale() по какой-либо причине завершается неудачно (например, при попытке установить неизвестную системе локаль), локаль для категории не изменяется, а функция возвращает undef.
Начиная с Perl 5.28, в многопоточных Perl, скомпилированных на системах, поддерживающих безопасные многопоточные операции с локали по POSIX 2008, эта функция не выполняет непосредственный вызов системной функции setlocale. Вместо этого используются безопасные многопоточные операции для имитации функции setlocale в безопасном для потоков режиме.
Вы можете принудительно использовать безопасные многопоточные операции с локали (если они доступны) при перекомпиляции Perl, добавив
-Accflags='-DUSE_THREAD_SAFE_LOCALE' в ваш вызов Configure.
Дополнительную информацию о категориях см. на странице 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 на системах, которые отключают многопоточные безопасные операции.
Обычно в однопоточных сборках используется традиционная функция setlocale(), а не безопасные для потоков функции локалей. Вы можете принудительно использовать эти функции на системах, которые их поддерживают, добавив -Accflags='-DUSE_THREAD_SAFE_LOCALE' в Configure.
Изначально программа запускается с локали, заданной в окружении, как описано в разделе "ОКРУЖЕНИЕ". Все вновь созданные потоки запускаются с LC_ALL, установленным в "C">. Каждый поток может использовать POSIX::setlocale() для запроса или изменения своей локали в любое время без влияния на другие потоки. Все операции, зависящие от локали, автоматически используют локаль текущего потока.
Это должно быть полностью прозрачно для всех приложений, написанных полностью на Perl (кроме нескольких редких исключений, описанных в разделе "Многопоточные"). Информация для авторов XS-модулей представлена в разделе "Locale-aware 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 из исходного кода, можно использовать файл lib/locale.t в наборе тестов Perl для проверки локалей вашей системы. Установка переменной окружения 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 можно запустить в локали "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» в латинских алфавитах, но куда относятся «á» и «å»? И хотя «color» следует за «chocolate» по-английски, что насчёт традиционного испанского?
Следующие сортировки имеют смысл, и вы можете встретить любую из них, если "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 Вот фрагмент кода, который показывает, какие символы «word» находятся в текущей локали, в порядке этой локали:
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 локалями, предоставляя разумную сортировку по умолчанию для кодовых точек, которые важны в этой локали. (И если они не работают хорошо, проблема может заключаться только в том, что определение локали неполно, поэтому может быть исправлена с помощью лучшего файла определения. Определения Unicode (см. "Свободно доступные определения локалей") предоставляют разумные определения сортировки локалей UTF-8.) Начиная с Perl v5.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 (см. "Магические переменные" в perlguts) создаёт преобразованную версию строки при первом её использовании в сравнении, а затем хранит эту версию на случай необходимости повторного использования. Переписанный пример простым способом с cmp выполняется примерно с той же скоростью. Он также справляется с нулевыми символами, встроенными в строки; если вы напрямую вызываете strxfrm(), он обрабатывает первый нулевой символ как терминатор. Не ожидайте, что преобразованные строки, которые он создаёт, будут портативными на разных системах — или даже между одной ревизией вашей операционной системы и следующей. Короче говоря, не вызывайте strxfrm() напрямую: позвольте Perl сделать это за вас.
Примечание: use locale не показан в некоторых из этих примеров, потому что он не нужен: strcoll() и strxfrm() — функции POSIX, которые используют стандартные системные функции libc, которые всегда следуют текущей локали LC_COLLATE.
Категория LC_CTYPE: Типы символов
В контексте формы use locale, включающей LC_CTYPE, Perl следует настройке локали LC_CTYPE. Это определяет представление приложения о том, какие символы являются алфавитными, цифровыми, пунктуационными и т. д. Это влияет на метанотацию \w регулярного выражения Perl, которая обозначает буквенно-цифровые символы — то есть алфавитные, цифровые и системный символ подчёркивания. (Обратитесь к 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'. Аналогично, все escape-последовательности для конкретных символов, \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: устаревшая сортировка
В версиях Perl до 5.004, сортировка с учетом локали была возможна с использованием модуля библиотеки I18N::Collate. Этот модуль теперь устарел и следует избегать в новых приложениях. Функциональность LC_COLLATE теперь интегрирована в ядро Perl: можно использовать локально-зависимые скалярные данные обычным образом с use locale, поэтому больше нет необходимости работать со скалярными ссылками I18N::Collate.
Скорость сортировки и использование памяти
Сравнение и сортировка с учетом локали обычно медленнее, чем по умолчанию; наблюдалось замедление в два-четыре раза. Это также потребует больше памяти: после того, как скалярная переменная Perl участвовала в любой операции сравнения строк или сортировки, подчиняющейся правилам сортировки с учетом локали, она будет занимать в 3-15 раз больше памяти, чем раньше. (Точный множитель зависит от содержимого строки, операционной системы и локали.) Эти недостатки обусловлены скорее реализацией системы локали операционной системой, чем Perl.
Свободно доступные определения локали
Проект Unicode CLDR извлекает часть POSIX многих своих локалей, доступных по адресу
https://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, поскольку ее первые и последние буквы разделены восемнадцатью другими. (Вы можете догадаться, почему сокращение internalin... internaliti... i18n так распространено.) Аналогично, «локализация» часто сокращается до l10n.
Несовершенный стандарт
Интернационализация, как определено в стандартах C и POSIX, может быть подвергнута критике как неполная и неуклюжая. Они также имеют тенденцию, как группы стандартов, делить мир на нации, когда всем известно, что мир можно также разделить на банкиров, байкеров, геймеров и так далее.
Unicode и UTF-8
Поддержка Unicode является новой, начиная с версии Perl v5.6, и более полно реализована в версиях v5.8 и более поздних. См. perluniintro.
Начиная с Perl v5.20, UTF-8 локали поддерживаются в Perl, за исключением 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 теперь опубликованы для каждой области мира (https://unicode.org/Public/cldr/2.0.1/ для уже настроенных, но из более ранней версии; https://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), вероятно, не будут работать из многопоточного приложения без изменений. См. "Локализованный код XS в perlxs".
Модуль XS, зависящий от локали, мог быть написан с предположением, что он никогда не будет вызван в многопоточной среде, и поэтому использует другие нелокализованные конструкции, которые не являются безопасными для многопоточности. См. "Многопоточные системные интерфейсы в perlxs".
POSIX не определяет способ получения имени текущей локали каждого потока. Некоторые системы, такие как Darwin и NetBSD, реализуют функцию querylocale(3) для этого. На системах, не являющихся Windows, без неё, таких как Linux, есть некоторые дополнительные оговорки:
-
Встроенный perl должен быть запущен, пока глобальная локаль активна. См. "Использование встроенного Perl с POSIX-локальностью в perlembed".
-
Для perl становится важнее знать обо всех возможных категориях локали на платформе, даже если они, по-видимому, не используются в вашей программе. Perl знает все категории Linux. Если ваша платформа имеет другие, вы можете создать вопрос на https://github.com/Perl/perl5/issues для включения её в следующий релиз. Тем временем можно отредактировать исходный код Perl, чтобы он узнавал о категории, и затем перекомпилировать. Поищите в исходном коде примеры, например,
LC_PAPER, и используйте их в качестве шаблона для добавления пропущенной. -
Возможны, хотя и трудно реализуемые, вызовы
POSIX::setlocaleс локалью, которую он не распознаёт как синтаксически корректную, но которая на самом деле является корректной на этой системе. Это должно происходить только с встроенными perl или если вы создаёте имя локали самостоятельно.
Неисправные системы
На некоторых системах поддержка локали операционной системы неисправна и не может быть исправлена или использована Perl. Такие недостатки могут и будут приводить к загадочным зависаниям и/или дампам ядра Perl, когда use locale активна. При столкновении с такой системой, пожалуйста, подробно сообщите об этом на <https://github.com/Perl/perl5/issues>, а также обратитесь к своему поставщику: исправления ошибок для этих проблем могут существовать в вашей операционной системе. Иногда такие исправления ошибок называются обновлением операционной системы. Если у вас есть исходный код Perl, включите в отчёт об ошибке вывод теста, описанного выше в "Тестирование на неисправные локали".
См. также
I18N::Langinfo, perluniintro, perlunicode, open, "localeconv" в POSIX, "setlocale" в POSIX, "strcoll" в POSIX, "strftime" в POSIX, "strtod" в POSIX, "strxfrm" в POSIX.
Дополнительные соображения при встроенном Perl в программе C см. в "Использование встроенного Perl с POSIX-локальностью в perlembed".
ИСТОРИЯ
Оригинальный perli18n.pod Джарко Хиетаниеми сильно модифицирован Домиником Данлопом, при содействии perl5-разработчиков. Проза немного переработана Томом Кристиансеном и теперь поддерживается разработчиками Perl 5.
© 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.32.0/perllocale