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. Начиная с версии 5.26, Perl может обрабатывать их также достаточно хорошо, в зависимости от реализации платформы. Однако для более ранних выпусков или для лучшего контроля используйте Unicode::Collate. На самом деле существует два немного разных типа UTF-8 локалей: один для тюркских языков и другой для всех остальных.
Начиная с версии Perl 5.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, НЕ используйте эту директиву в скриптах с несколькими активными потоками. Локаль в этих случаях не локальна для одного потока. Другой поток может изменить локаль в любой момент, что может, как минимум, привести к тому, что данный поток работает в локали, в которой он не ожидал работать. На некоторых платформах также могут возникнуть сегментно-нарушенные ошибки. Изменение локали необязательно должно быть явным; некоторые операции заставляют сам 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 поддерживает проверку на заражение), поскольку локаль может быть ненадежной. См. "БЕЗОПАСНОСТЬ".
Начиная с 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. Только один аргумент категории может быть указан в use locale если он имеет отрицательную форму.
До версии 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 или на системах, которые не поддерживают многопоточную работу с локалью, НЕ используйте эту функцию в потоке. Локаль будет меняться во всех других потоках одновременно, и если ваш поток приостановится операционной системой, а другой стартует, этот поток не получит ожидаемую локаль. На некоторых платформах может возникнуть гонка, приводящая к сегментно-нарушенным ошибкам, если две нити вызывают эту функцию почти одновременно. Это предупреждение не относится к однопоточным сборкам или к версиям Perl, где ${^SAFE_LOCALES} существует и не равно нулю; а именно Perl 5.28 и более поздние версии, однопоточные или скомпилированные для многопоточной работы с локалью. На системах z/OS эта функция становится бесполезной после запуска любого потока. Таким образом, на этой системе вы можете настроить локаль до создания потоков, и эта локаль будет действовать для всей программы.
В противном случае, вы можете переключаться между локалями так часто, как захотите, во время выполнения с помощью функции %%%CODE_BLOCK_107%%:
# 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 code" в 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 Multinational Character Set (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" в латинских алфавитах, но где находятся "á" и "å"? И в то время как "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 Вот фрагмент кода, который показывает, какие символы "слова" содержатся в текущей локали, в порядке этой локали:
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.
Начиная с версии 5.20, Perl поддерживает локаль UTF-8 для LC_CTYPE, но в противном случае Perl поддерживает только однобайтовые локали, такие как серии ISO 8859. Это означает, что локали с широким набором символов, например, для азиатских языков, не поддерживаются должным образом. Использование этих локалей может привести к сбою ядра. Если платформа предоставляет Perl возможность распознавать такую локаль, начиная с Perl версии 5.22, Perl будет выводить предупреждение, по умолчанию включенное, используя категорию предупреждений locale, всякий раз, когда такая локаль переключается. Поддержка локали UTF-8 фактически является надмножеством локалей POSIX, поскольку она обеспечивает полное поведение Юникода, как будто никакая локаль LC_CTYPE не активна (кроме маркировки; см. "SECURITY"). Локали POSIX, даже UTF-8, лишены определённых концепций Юникода, таких как идея, что изменение регистра символа может расшириться до более чем одного символа. Perl в локали UTF-8 предоставит вам это расширение. До версии 5.20 Perl на некоторых платформах обрабатывал локаль UTF-8 как локаль ISO 8859-1 с некоторыми ограничениями, а на других платформах — как локаль «C». Для выпусков 5.16 и 5.18, use locale 'not_characters можно было использовать в качестве обходного решения для этого (см. "Unicode и UTF-8").
Обратите внимание, что довольно много вещей не зависят от текущей локали. Любой литеральный символ — это родной символ для данной платформы. Таким образом, «A» означает символ с кодовым значением 65 на платформах ASCII и 193 на платформах EBCDIC. Это может или не может быть «A» в текущей локали, если в этой локали вообще есть «A». Аналогично, все управляющие последовательности для конкретных символов, \n например, всегда означают родной символ платформы. Это означает, что, например, \N в регулярных выражениях (любой символ, кроме новой строки) работает с набором символов платформы.
Начиная с версии 5.22, Perl будет по умолчанию предупреждать о переключении в локаль, которая переопределяет любой печатаемый символ ASCII (плюс \t и \n) в класс, отличный от ожидаемого. Это, вероятно, произойдёт на современных локалях только на платформах EBCDIC, где, например, локаль CCSID 0037 на машине CCSID 1047 перемещает "[", но это может произойти на платформах ASCII с локалями ISO 646 и другими 7-битовыми локалями, которые в основном устарели. Функционирование может сохраниться в зависимости от того, какие функции Perl используются программой. Например, в примере выше, где "|" становится \w, и нет регулярных выражений, где это имеет значение, программа может всё же работать правильно. Предупреждение перечисляет все символы, которые, по его определению, могут быть негативно затронуты.
Примечание: Некорректное или злонамеренное определение локали LC_CTYPE может привести к тому, что явно неприемлемые символы будут считаться буквенно-цифровыми в вашем приложении. Для строгого соответствия (обычных) букв и цифр ASCII, например, в командах, приложения, учитывающие локаль, должны использовать \w с модификатором регулярного выражения /a. См. "SECURITY".
Категория 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), чтобы отметить результаты строк, которые зависят от локали и которые могут быть небезопасными в результате.
Обратите внимание, что Perl можно скомпилировать без поддержки маркировки, в этом случае все функции маркировки молча ничего не делают.
Вот сводка поведения маркировки операторов и функций, которые могут быть затронуты локалью:
-
Операторы сравнения (
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 затем используется системная локаль по умолчанию. Если всё остальное не работает, что-то сильно неисправно, но 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 часть многих своих локалей, доступных по адресу
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, вы получите менее идеальное поведение, описанное ниже, которое вы получаете с Perls до 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 локалей в Perls (до 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 для тех, которые не могут, не применяется равномерно. В версиях до v5.12 это было несколько произвольно; в v5.12 оно довольно последовательно применялось к соответствию регулярных выражений, за исключением скобочных классов символов; в v5.14 оно было расширено на все соответствия регулярным выражениям; а в v5.16 на операции преобразования регистра, такие как \L и uc(). Для сортировки во всех выпусках до сих пор вызывается функция системы strxfrm(), и то, что она делает, — это то, что вы получаете. Начиная с v5.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) для этого. На системах, не использующих Windows, без этой функции, таких как Linux, существуют дополнительные замечания:
-
Встроенный Perl необходимо запускать, когда глобальная локаль активна. См. "Using embedded Perl with POSIX locales" в 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, включите в отчет об ошибке вывод теста, описанного выше в "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 от Jarkko Hietaniemi был значительно изменен Dominic Dunlop, при содействии perl5-porters. Текст был переработан Tom Christiansen, и теперь поддерживается Perl 5 porters.
© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.36.0/perllocale