perllocale
СОДЕРЖАНИЕ
- НАЗВАНИЕ
- ОПИСАНИЕ
- ЧТО ТАКОЕ ЛОКАЛЬ
- ПРЕДВАРИТЕЛЬНАЯ ПОДГОТОВКА К ИСПОЛЬЗОВАНИЮ ЛОКАЛЕЙ
- ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ
- Предикат "use locale"
- Функция setlocale
- Многопоточная работа
- Поиск локалей
- ПРОБЛЕМЫ С ЛОКАЛЯМИ
- Проверка на неисправные локали
- Временное исправление проблем с локалью
- Постоянное исправление проблем с локалью
- Постоянное исправление конфигурации локалей системы
- Исправление конфигурации системной локали
- Функция localeconv
- I18N::Langinfo
- КАТЕГОРИИ ЛОКАЛЕЙ
- БЕЗОПАСНОСТЬ
- ОКРУЖЕНИЕ
- ПРИМЕЧАНИЯ
- Unicode и UTF-8
- ОШИБКИ
- СМОТРИТЕ ТАКЖЕ
- ИСТОРИЯ
НАЗВАНИЕ
perllocale — Обработка локалей в Perl (интернационализация и локализация)
ОПИСАНИЕ
Вначале был ASCII, «American Standard Code for Information Interchange», который работает довольно хорошо для американцев с их английским алфавитом и валютой в долларах. Но он не очень хорошо работает даже для других англоговорящих людей, которые могут использовать разные валюты, такие как британский фунт (так как символ этой валюты не в ASCII); и он совершенно непригоден для многих тысяч других языков мира.
Для решения этих недостатков была изобретена концепция локалей (формально ISO C, XPG4, POSIX 1.c «система локалей»). И приложения пишутся и используются, которые используют механизм локалей. Процесс адаптации такого приложения к предпочтениям пользователей в таких вопросах называется интернационализацией (часто сокращенно i18n); информирование такого приложения о конкретном наборе предпочтений известно как локализация (l10n).
Perl был расширен для поддержки определенных типов локалей, доступных в системе локалей. Это контролируется в каждом приложении с помощью одного предиката, одного вызова функции и нескольких переменных окружения.
Perl поддерживает однобайтовые локали, которые являются надмножествами ASCII, такие как ISO 8859, и одну многобайтовую локаль UTF-8, описанную в следующем абзаце. Perl не поддерживает никакие другие многобайтовые локали, такие как те, которые предназначены для восточноазиатских языков.
К сожалению, в разработке (и часто в реализациях) локалей есть довольно много недостатков. Unicode был изобретен (см. perlunitut для введения в него), отчасти для решения этих недостатков в проектировании, и в наши дни есть ряд «UTF-8 локалей», основанных на Unicode. Это локали, у которых набор символов — Unicode, закодированный в UTF-8. Начиная с версии 5.20, Perl полностью поддерживает UTF-8 локали, за исключением сортировки и сравнения строк, типа lt и ge. Начиная с версии 5.26, Perl может обрабатывать эти вещи приемлемо, в зависимости от реализации платформы. Однако для более ранних релизов или для лучшего контроля используйте Unicode::Collate. На самом деле существует два немного отличающихся типа UTF-8 локалей: один для тюркских языков и один для всех остальных. Начиная с Perl v5.30, 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, НЕ используйте эту директиву в скриптах с несколькими активными потоками. Локаль в этих случаях не локальна для одного потока. Другой поток может изменить локаль в любое время, что может привести, как минимум, к тому, что данный поток будет работать в локали, которой он не ожидал. На некоторых платформах могут также возникать ошибки segfault. Изменение локали не обязательно должно быть явным; некоторые операции заставляют Perl изменить локаль самостоятельно. Вы уязвимы просто выполнив "use locale".
По умолчанию Perl сам (вне модуля POSIX) игнорирует текущую локаль. Директива use locale сообщает Perl использовать текущую локаль для некоторых операций. Начиная с v5.16, к этой директиве доступны необязательные параметры, описанные ниже, которые ограничивают, какие операции на нее влияют.
Текущая локаль устанавливается во время выполнения функцией setlocale(), описанной ниже. Если эта функция ещё не была вызвана в ходе выполнения программы, текущей локалью является та, которая была определена переменными среды "СРЕДА", действующими в начале программы. Если нет действительных переменных среды, текущей локалью является системная локаль по умолчанию. В системах POSIX это, скорее всего, но не обязательно, локаль "C". В Windows по умолчанию она устанавливается через Control Panel->Regional and Language Options компьютера (или её современный аналог).
Операции, на которые влияет локаль:
-
Не в области действия
"use locale" -
Только определённые операции (все, исходящие за пределами Perl) должны быть затронуты, как указано ниже:
-
Текущая локаль используется при выходе за пределы Perl с операциями, такими как system() или qx//, если эти операции чувствительны к локали.
-
Также Perl предоставляет доступ к различным функциям библиотеки C через модуль POSIX. Некоторые из этих функций всегда зависят от текущей локали. Например,
POSIX::strftime()используетLC_TIME;POSIX::strtod()используетLC_NUMERIC;POSIX::strcoll()иPOSIX::strxfrm()используютLC_COLLATE. Все такие функции будут вести себя в соответствии с текущей базовой локалью, даже если эта локаль не представлена в пространстве Perl.Это также относится к I18N::Langinfo.
-
Модули XS для всех категорий, кроме
LC_NUMERIC, получают базовую локаль, и, следовательно, все функции библиотеки C, которые они вызывают, будут использовать эту базовую локаль. Для получения более подробной информации см. "ОСОБЕННОСТИ" в perlxs.
Обратите внимание, что все программы C (включая интерпретатор Perl, написанный на C) всегда имеют базовую локаль. Эта локаль является локалью "C", если не изменена вызовом setlocale(). При запуске Perl он изменяет базовую локаль на ту, которая указана в "СРЕДЕ". При использовании модуля POSIX или написании кода XS важно помнить, что базовая локаль может быть другой, чем "C", даже если программа её явно не изменила.
-
-
Остаточные эффекты
use locale -
Определённые операции Perl, настроенные в области действия
use locale, сохраняют это действие даже вне области действия. К ним относятся:-
Формат вывода функции write() определяется более ранним объявлением формата ("формат" в perlfunc), поэтому то, влияет ли вывод на локаль, определяется тем, находится ли
format()в области действияuse locale, а не тем, находится лиwrite()в ней. -
Образцы регулярных выражений могут быть скомпилированы с использованием qr// с отложенным фактическим сопоставлением на более поздний этап. Опять же, именно то, находилась ли компиляция в пределах области действия
use locale, определяет поведение сопоставления, а не то, производятся ли сопоставления внутри такой области действия или нет.
-
-
В рамках
"use locale"; -
-
Все вышеперечисленные операции
-
Определения форматов ("формат" в perlfunc) и, следовательно, все последующие
write()используютLC_NUMERIC. -
Преобразование строк и вывод используют
LC_NUMERIC. К ним относятся результатыprint(),printf(),say(), иsprintf(). -
Операторы сравнения (
lt,le,cmp,ge, иgtиспользуютLC_COLLATE.sort()также затрагивается, если используется без явной функции сравнения, поскольку она по умолчанию используетcmp.Примечание:
eqиneне зависят от локали: они всегда выполняют сравнение посимвольно своих скалярных операндов. Более того, еслиcmpобнаружит, что её операнды равны в соответствии с порядком сортировки, заданным текущей локалью, она переходит к посимвольному сравнению, и возвращает 0 (равно) только если операнды идентичны посимвольно. Если вам действительно нужно узнать, равны ли две строки — которыеeqиcmpмогут рассматривать по-разному — с точки зрения сортировки в локали, см. обсуждение в "КатегорияLC_COLLATE: Сортировка". -
Регулярные выражения и функции изменения регистра (
uc(),lc(),ucfirst(), иlcfirst()используютLC_CTYPE -
Переменные $! (и её синонимы
$ERRNOи$OS_ERROR) и $^E (и её синоним$EXTENDED_OS_ERROR), когда используются как строки, используютLC_MESSAGES.
-
По умолчанию поведение восстанавливается с помощью директивы no locale или по достижении конца блока, содержащего use locale. Обратите внимание, что вызовы use locale могут быть вложенными, и то, что действует внутри внутреннего блока, вернётся к правилам внешнего блока по окончании внутреннего.
Строковый результат любой операции, использующей информацию о локали, считается заражённым, так как локаль может быть ненадежной. См. "БЕЗОПАСНОСТЬ".
Начиная с Perl v5.16, в очень ограниченном виде, а более общим образом с v5.22, вы можете ограничить, какие категории включены в этот конкретный экземпляр директивы, добавив параметры к ней. Например,
use locale qw(:ctype :numeric); включает осведомлённость о локали в пределах её области действия только для тех операций (перечисленных выше), которые затронуты LC_CTYPE и LC_NUMERIC.
Возможные категории: :collate, :ctype, :messages, :monetary, :numeric, :time, и псевдокатегория :characters (описанная ниже).
Таким образом, вы можете сказать
use locale ':messages'; и только $! и $^E будут учитывать локаль. Всё остальное не затронуто.
Поскольку Perl в настоящее время ничего не делает с категорией LC_MONETARY, указание :monetary фактически ничего не меняет. Некоторые системы имеют другие категории, такие как LC_PAPER, но Perl также не выполняет с ними никаких действий, и нет способа указать их в аргументах этой директивы.
Вы также можете легко сказать, что использовать все категории, кроме одной, например,
use locale ':!ctype';
use locale ':not_ctype'; оба из которых означают включение осведомлённости о локали для всех категорий, кроме LC_CTYPE. В отрицательной форме может быть указан только один аргумент категории в use locale.
До версии v5.22 доступна только одна форма директивы с аргументами:
use locale ':not_characters'; (и вам нужно сказать not_; вы не можете использовать форму с восклицательным знаком !). Эта псевдокатегория — сокращение для указания как :collate так и :ctype. Следовательно, в отрицательной форме это почти то же самое, что сказать
use locale qw(:messages :monetary :numeric :time); Мы используем термин «почти», потому что :not_characters также включает use feature 'unicode_strings' в своей области действия. Эта форма менее полезна в v5.20 и более поздних версиях, и подробно описана в "Юникод и UTF-8", но кратко, она сообщает Perl не использовать части определения локали, то есть категории LC_CTYPE и LC_COLLATE. Вместо этого она будет использовать родную кодировку символов (расширенную Unicode). При использовании этого параметра вы несете ответственность за перевод внешней кодировки символов в родную/Unicode (которая уже будет таковой, если это одна из всё более популярных UTF-8 локалей). Существуют удобные способы сделать это, как описано в "Юникод и UTF-8".
Функция setlocale
ВНИМАНИЕ! До Perl 5.28 или на системах, не поддерживающих потокобезопасные операции с локалью, НЕ используйте эту функцию в потоке. Локаль изменится во всех других потоках одновременно, и если ваш поток будет приостановлен операционной системой, а другой запущен, этот поток не будет иметь ожидаемой локали. На некоторых платформах может возникнуть гонка, приводящая к ошибкам segfault, если две нити вызывают эту функцию почти одновременно.
Вы можете изменять локаль так часто, как пожелаете, во время выполнения с помощью функции POSIX::setlocale():
# Import locale-handling tool set from POSIX module.
# This example uses: setlocale -- the function call
# LC_CTYPE -- explained below
# (Showing the testing for success/failure of operations is
# omitted in these examples to avoid distracting from the main
# point)
use POSIX qw(locale_h);
use locale;
my $old_locale;
# query and save the old locale
$old_locale = setlocale(LC_CTYPE);
setlocale(LC_CTYPE, "fr_CA.ISO8859-1");
# LC_CTYPE now in locale "French, Canada, codeset ISO 8859-1"
setlocale(LC_CTYPE, "");
# LC_CTYPE now reset to the default defined by the
# LC_ALL/LC_CTYPE/LANG environment variables, or to the system
# default. See below for documentation.
# restore the old locale
setlocale(LC_CTYPE, $old_locale); Первый аргумент setlocale() задаёт категорию, второй — локаль. Категория указывает, в каком аспекте обработки данных необходимо применить правила, специфичные для локали. Имена категорий обсуждаются в "КАТЕГОРИЯХ ЛОКАЛЕЙ" и "СРЕДЕ". Локаль — это имя набора настроек, соответствующих определённому сочетанию языка, страны или территории и кодовой страницы. Читайте далее для подсказок по именованию локалей: не все системы используют именование локалей так, как показано в примере.
Если второй аргумент не указан, а категория отличается от LC_ALL, функция возвращает строку, содержащую имя текущей локали для заданной категории. Вы можете использовать это значение в качестве второго аргумента в последующем вызове setlocale(), но на некоторых платформах строка является непрозрачной, её значение локали большинство людей не сможет расшифровать.
Если второй аргумент не указан, а категория равна LC_ALL, результат зависит от реализации. Он может быть строкой, состоящей из конкатенированных имён локалей (разделитель также зависит от реализации), или единственным именем локали. Обратитесь к странице справки setlocale(3) для получения подробной информации.
Если второй аргумент задан и соответствует допустимой локали, локаль для категории устанавливается в это значение, а функция возвращает текущее значение локали. Вы можете использовать это значение в ещё одном вызове setlocale(). (В некоторых реализациях возвращаемое значение может отличаться от значения, предоставленного в качестве второго аргумента — представьте это как псевдоним для предоставленного вами значения.)
Как показывает пример, если второй аргумент является пустой строкой, локаль категории возвращается к значению по умолчанию, указанному соответствующими переменными среды. Как правило, это приводит к возврату значения по умолчанию, действующего при запуске Perl: изменения в среде, внесённые приложением после запуска, могут или не могут быть учтены, в зависимости от библиотеки C вашей системы.
Обратите внимание, что когда используется форма use locale без указания всех категорий, Perl игнорирует исключённые категории.
Если set_locale() по какой-либо причине завершается неудачно (например, при попытке установить локаль, неизвестную системе), локаль для категории не изменяется, и функция возвращает undef.
Начиная с Perl 5.28, в многопоточных Perl-интерпретаторах, скомпилированных на системах, которые поддерживают безопасные для потоков операции с локали в соответствии с POSIX 2008, эта функция фактически не вызывает системную функцию setlocale. Вместо этого используются безопасные для потоков операции, чтобы эмулировать функцию setlocale, но в безопасном для потоков режиме.
Вы можете принудительно использовать безопасные для потоков операции с локали (если они доступны) при перекомпиляции 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 Вот фрагмент кода, который показывает, какие символы "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. Это управляет представлением приложения о том, какие символы являются буквенными, числовыми, пунктуационными и т. д. Это влияет на метанотацию Perl \w регулярных выражений, которая обозначает буквенно-цифровые символы — то есть, буквенные, цифровые и платформенные символы подчеркивания. (См. perlre для получения дополнительной информации о регулярных выражениях.) Благодаря LC_CTYPE, в зависимости от вашей настройки локали, такие символы, как «æ», «ð», «ß» и «ø», могут пониматься как \w символы. Это также влияет на такие вещи, как \s, \D, и классы символов POSIX, такие как [[:graph:]]. (См. perlrecharclass для получения дополнительной информации обо всех этих элементах.)
Локаль LC_CTYPE также предоставляет карту, используемую при транслитерации символов между прописными и строчными буквами. Это влияет на функции преобразования регистра—fc(), lc(), lcfirst(), uc(), и ucfirst(); интерполяцию преобразования регистра с \F, \l, \L, \u, или \U в двойных кавычках и s/// замещениями; и поиск по шаблонам регулярных выражений без учёта регистра с использованием модификатора i.
Начиная с версии v5.20, Perl поддерживает UTF-8 локаль для LC_CTYPE, но в противном случае Perl поддерживает только локаль с одним байтом, например, серии ISO 8859. Это означает, что локаль с широким набором символов, например, для азиатских языков, не поддерживается должным образом. Использование этих локалей может привести к сбою ядра. Если платформа предоставляет Perl возможность обнаружения такой локали, начиная с Perl v5.22, Perl будет выдавать предупреждение (по умолчанию включено) с использованием категории предупреждений locale, всякий раз, когда такая локаль переключается. Поддержка UTF-8 локали фактически является надмножеством POSIX локалей, потому что она представляет собой полное поведение Unicode, как будто никакая LC_CTYPE локаль не действовала (за исключением загрязнения; см. "БЕЗОПАСНОСТЬ"). POSIX локаль, даже UTF-8, лишена определенных понятий в Unicode, например, идеи о том, что изменение регистра символа может расшириться до нескольких символов. Perl в UTF-8 локали предоставит это расширение. До версии v5.20 Perl на некоторых платформах рассматривал UTF-8 локаль как ISO 8859-1, с некоторыми ограничениями, а на других платформах — как локаль "C". Для версий v5.16 и v5.18, use locale 'not_characters можно было использовать в качестве обходного решения (см. "Unicode и UTF-8").
Обратите внимание, что довольно много вещей не зависят от текущей локали. Любой литерный символ — это родной символ для данной платформы. Следовательно, 'A' означает символ с кодовым значением 65 на платформах ASCII и 193 на платформах EBCDIC. Это может или не может быть 'A' в текущей локали, если эта локаль вообще имеет 'A'. Аналогично, все последовательности для ввода-вывода определённых символов, \n например, всегда означают родной символ платформы. Это означает, например, что \N в регулярных выражениях (любой символ, кроме новой строки) работает с набором символов платформы.
Начиная с версии v5.22, Perl по умолчанию будет выводить предупреждение при переключении на локаль, которая переопределяет любые печатаемые символы ASCII (плюс \t и \n) в класс, отличный от ожидаемого. Это, скорее всего, произойдёт на современных локалях только на платформах EBCDIC, где, например, локаль CCSID 0037 на машине CCSID 1047 перемещает "[", но это может произойти на платформах ASCII с локалями ISO 646 и другими 7-битовыми локалями, которые в основном устарели. Вещи могут по-прежнему работать, в зависимости от функций Perl, используемых программой. Например, в примере выше, где "|" становится \w, и нет регулярных выражений, где это имеет значение, программа может по-прежнему работать правильно. Предупреждение перечисляет все символы, которые, как можно определить, могут быть негативно затронуты.
Примечание: Неправильно сконфигурированная или вредоносная LC_CTYPE локаль может привести к тому, что явно неподходящие символы будут считаться буквенно-цифровыми вашей программой. Для строгого сопоставления (обычных) букв и цифр ASCII — например, в командных строках — приложения, учитывающие локаль, должны использовать \w с модификатором регулярного выражения /a. См. "БЕЗОПАСНОСТЬ".
Категория LC_NUMERIC: Форматирование чисел
После вызова правильной POSIX::setlocale() функции и в пределах области use locale формы, содержащей числа, Perl подчиняется информации локали LC_NUMERIC, которая управляет представлением программы о том, как числа должны форматироваться для удобства чтения человеком. В большинстве реализаций единственным эффектом является изменение символа, используемого для десятичной точки — возможно, с "." на ",". Функции не учитывают такие тонкости, как разделение тысяч и т. д. (См. "Функция localeconv", если вам важны эти вещи.)
use POSIX qw(strtod setlocale LC_NUMERIC);
use locale;
setlocale LC_NUMERIC, "";
$n = 5/2; # Assign numeric 2.5 to $n
$a = " $n"; # Locale-dependent conversion to string
print "half five is $n\n"; # Locale-dependent output
printf "half five is %g\n", $n; # Locale-dependent output
print "DECIMAL POINT IS COMMA\n"
if $n == (strtod("2,5"))[0]; # Locale-dependent conversion См. также I18N::Langinfo и RADIXCHAR.
Категория LC_MONETARY: Форматирование денежных сумм
Стандарт C определяет категорию LC_MONETARY, но не функцию, которая зависит от её содержимого. (Те, кто имеет опыт работы с комитетами по стандартам, поймут, что рабочая группа решила обойти этот вопрос.) Соответственно, Perl по существу не обращает на него внимания. Если вы действительно хотите использовать LC_MONETARY, вы можете запросить её содержимое — см. "Функцию localeconv" — и использовать полученную информацию в собственном форматировании денежных сумм вашего приложения. Однако вы можете обнаружить, что информация, хотя и объёмная и сложная, всё ещё не удовлетворяет вашим потребностям: форматирование валюты — сложная задача.
См. также I18N::Langinfo и CRNCYSTR.
Категория LC_TIME: Представление времени
Выходные данные, созданные POSIX::strftime(), которые строят отформатированную строку человекочитаемого даты/времени, зависят от текущей LC_TIME локали. Таким образом, во французской локали выходные данные, созданные элементом формата %B (полное название месяца) для первого месяца года, будут "janvier". Вот как получить список полных названий месяцев в текущей локали:
use POSIX qw(strftime);
for (0..11) {
$long_month_name[$_] =
strftime("%B", 0, 0, 0, 1, $_, 96);
} Примечание: use locale не требуется в этом примере: strftime() — это функция POSIX, которая использует стандартную функцию libc, предоставляемую системой, которая всегда подчиняется текущей LC_TIME локали.
См. также I18N::Langinfo и ABDAY_1..ABDAY_7, DAY_1..DAY_7, ABMON_1..ABMON_12, и ABMON_1..ABMON_12.
Другие категории
Остальные категории локалей в настоящее время не используются самим Perl. Но опять же, обратите внимание, что другие вещи, с которыми взаимодействует Perl, могут использовать их, включая расширения за пределами стандартного дистрибутива Perl, а также операционную систему и её утилиты. Обратите особое внимание на то, что строковое значение $! и сообщения об ошибках, выдаваемые внешними утилитами, могут изменяться LC_MESSAGES. Если вам нужны переносимые коды ошибок, используйте %!. См. Errno.
БЕЗОПАСНОСТЬ
Хотя основное обсуждение проблем безопасности Perl можно найти в perlsec, обсуждение обработки локалей Perl было бы неполным, если бы оно не обратило ваше внимание на проблемы безопасности, связанные с локалями. Локали — особенно на системах, которые позволяют обычным пользователям создавать свои собственные локальные настройки — ненадёжны. Вредная (или просто некорректно настроенная) локаль может привести к неожиданным результатам у приложения, учитывающего локаль. Вот несколько возможных вариантов:
-
Проверки регулярных выражений на безопасность имён файлов или адресов электронной почты с использованием
\wмогут быть обойденыLC_CTYPEлокалью, которая утверждает, что символы, такие как">"и"|"являются буквенно-цифровыми. -
Интерполяция строк с преобразованием регистра, как, например, в
$dest = "C:\U$name.$ext", может привести к опасным результатам, если используется ложныйLC_CTYPEтаблица преобразования регистра. -
Хитрая
LC_COLLATEлокаль может привести к тому, что имена студентов с оценкой "D" будут появляться раньше, чем у тех, у кого "A". -
Приложение, которое утруждается использованием информации в
LC_MONETARY, может форматировать дебетовые операции так, как будто они кредиты, и наоборот, если эта локаль была скомпрометирована. Или же оно может производить платежи в долларах США вместо гонконгских долларов. -
Даты и названия дней в датах, отформатированных с помощью
strftime(), могут быть изменены в пользу злоумышленника, способного нарушитьLC_DATEлокаль. ("Посмотрите — там сказано, что я не был в здании в воскресенье.")
Эти опасности не специфичны для системы локалей: любой аспект среды приложения, который может быть изменён злонамеренно, представляет аналогичные проблемы. Аналогично, они не специфичны для Perl: любой язык программирования, который позволяет вам писать программы, учитывающие их среду, подвергает вас этим проблемам.
Perl не может защитить вас от всех возможностей, показанных в примерах — нет замены для вашей собственной бдительности — но, когда use locale активно, Perl использует механизм загрязнения (см. perlsec), чтобы помечать результаты строк, которые зависят от локали, и которые могут быть ненадежны в результате. Вот краткий обзор поведения загрязнения операторов и функций, которые могут зависеть от локали:
-
Операторы сравнения (
lt,le,ge,gtиcmp):Скалярный результат true/false (или меньше/равно/больше) никогда не заражён.
-
Интерполяция преобразования регистра (с
\l,\L,\u,\U, или\F)Строка результата, содержащая интерполированный материал, заражена, если используется форма
use locale, включающаяLC_CTYPE. -
Оператор сопоставления (
m//):Скалярный результат true/false никогда не заражён.
Все подмаски, предоставленные как результат контекста списка или как
$1и т.д., заражены, если используется формаuse locale, включающаяLC_CTYPE, и подмаска содержит зависимые от локали конструкции регулярного выражения. Эти конструкции включают\w(для сопоставления алфавитно-цифрового символа),\W(неалфавитно-цифрового символа),\bи\B(границы и неграницы слов, которые зависят от того, что\wи\Wсоответствуют),\s(пробельный символ),\S(непробельный символ),\dи\D(цифры и нецифры), а также POSIX-классы символов, такие как[:alpha:](см. ""POSIX Character Classes" в perlrecharclass").Заражение также возможно, если шаблон сопоставляется без учёта регистра (через
/i). Исключением являются случаи, когда все сопоставляемые символы кодируются выше 255 и не имеют преобразований в Unicode до значений ниже 256. Заражения не выполняется для таких случаев, так как Perl использует только правила Unicode для таких символов, а эти правила одинаковы независимо от текущей локали.Переменные, сопоставляющие шаблон,
$&,$`(префикс),$'(постфикс) и$+(последнее совпадение), также заражены. -
Оператор подстановки (
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). Кроме того, это не единственное значение, а «путь» (список, разделенный двоеточием), состоящий из языков (не локалей). См. документацию библиотеки 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-приложение учитывало информацию о локали, вы обязательно должны использовать pragma use locale (см. "Pragma \"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.
Скорость сортировки и использование памяти
Сравнение и сортировка с учетом локали обычно медленнее, чем стандартная сортировка; наблюдалось замедление в 2-4 раза. Также будет использоваться больше памяти: как только переменная скаляр Perl участвовала в какой-либо операции сравнения строк или сортировки, подчиняющейся правилам сортировки локали, она будет занимать в 3-15 раз больше памяти, чем раньше. (Точный множитель зависит от содержимого строки, операционной системы и локали.) Эти недостатки больше диктуются реализацией системы локали операционной системы, чем Perl.
Доступные наборы локализации
Проект Unicode CLDR извлекает позиксовую часть многих своих локали, доступные по адресу
http://unicode.org/Public/cldr/2.0.1/ (Более новые версии CLDR требуют самостоятельного вычисления данных POSIX. См. http://unicode.org/Public/cldr/latest/.)
Большая коллекция наборов локализации находится по адресу:
http://std.dkuug.dk/i18n/WG15-collection/locales/ Следует учитывать, что она не поддерживается и не претендует на пригодность для любых целей. Если ваша система позволяет устанавливать произвольные локали, вы можете найти эти наборы полезными в их текущем виде или как основу для разработки собственных локали.
I18n и l10n
«Интернационализация» часто сокращается до i18n, потому что первые и последние буквы разделены восемнадцатью другими. (Вы можете догадаться, почему внутренняя... интернационализац... i18n склонна к сокращению). Аналогично, «локализация» часто сокращается до l10n.
Несовершенный стандарт
Интернационализация, как определено в стандартах C и POSIX, может быть подвергнута критике за неполноту и громоздкость. Они также, как и группы стандартов, склонны делить мир на нации, когда мы все знаем, что мир можно одинаково хорошо разделить на банкиров, байкеров, геймеров и так далее.
Unicode и UTF-8
Поддержка Unicode появилась в версии Perl v5.6, а в версиях v5.8 и более поздних она реализована более полно. См. perluniintro.
Начиная с Perl v5.20, в Perl поддерживаются UTF-8 локали, за исключением LC_COLLATE, которая поддерживается лишь частично; поддержка сортировки улучшена в Perl v5.26 до уровня, который может быть достаточным для ваших потребностей (см. "Раздел LC_COLLATE: Сортировка: Сравнение текста и сортировка").
Если у вас Perl v5.16 или v5.18 и вы не можете обновить, вы можете использовать
use locale ':not_characters'; При использовании этой формы псевдонима Perl использует только несимвольные части локали, например LC_NUMERIC. Perl предполагает, что вы преобразовали все символы, с которыми он работает, в Unicode (фактически, в собственную кодировку платформы (ASCII или EBCDIC) плюс Unicode). Для данных в файлах это удобно сделать, также указав
use open ':locale'; Этот псевдоним обеспечивает преобразование всех входных данных из файлов в Unicode из текущей локали, заданной в окружении (см. "СРЕДА"), и всех выходных данных в файлы обратно в локаль. (См. open). На уровне каждого файлового дескриптора вы можете вместо этого использовать модуль PerlIO::locale или модуль Encode::Locale, оба доступны из CPAN. Последний модуль также имеет методы для облегчения обработки ARGV и переменных среды и может использоваться для отдельных строк. Если вы знаете, что все ваши локали будут UTF-8, как многие из них сейчас, вы можете использовать команду -C.
Эта форма псевдонима позволяет практически бесшовную обработку локали с Unicode. Порядок сортировки будет по порядку кодов Unicode. Unicode::Collate можно использовать для получения сортировки по правилам Unicode.
Все описанные модули и переключатели можно использовать в v5.20 просто с use locale, и, если входные локали не UTF-8, вы получите менее идеальное поведение, описанное ниже, то, которое вы получаете с Perl-ами до v5.16, или когда вы используете псевдоним локали без параметра :not_characters в v5.16 и v5.18. Если вы используете исключительно UTF-8 локали в v5.20 и выше, остальная часть этого раздела для вас неактуальна.
Есть два случая: многобайтные и однобайтные локали. Сначала многобайтные:
Единственная многобайтная (или многосимвольная) локаль, которую Perl, скорее всего, будет поддерживать, — это UTF-8. Это связано со сложностью реализации, тем, что сейчас опубликованы локали UTF-8 высокого качества для каждого региона мира (http://unicode.org/Public/cldr/2.0.1/ для уже настроенных, но из более ранней версии; http://unicode.org/Public/cldr/latest/ для самых актуальных, но вам нужно самостоятельно извлечь информацию POSIX), и, если всё это не подходит, вы можете использовать модуль Encode для преобразования в/из вашей локали. Так что вам придётся сделать что-то из этого, если вы используете одну из этих локали, такую как Big5 или Shift JIS. Для UTF-8 локали в Perl (до v5.20), которые не имеют полной поддержки UTF-8 локали, они могут работать достаточно хорошо (в зависимости от реализации вашей библиотеки C), просто потому, что и они, и Perl хранят символы, занимающие несколько байтов, одинаковым образом. Однако некоторые, если не большинство, реализации библиотек C могут не обрабатывать символы в верхней половине диапазона Latin-1 (128 - 255) должным образом под LC_CTYPE. Чтобы определить, является ли символ определенного типа в рамках локали, Perl использует функции, такие как isalnum(). Ваша библиотека C может не работать с UTF-8 локалями с этими функциями, вместо этого работая только с новыми функциями широкой библиотеки, такими как iswalnum(), которых Perl не использует. Эти многобайтовые локали обрабатываются как однобайтовые локали и имеют ограничения, описанные ниже. Начиная с Perl v5.22, выводится сообщение об ошибке, когда Perl обнаруживает многобайтовую локаль, которую он не полностью поддерживает.
Для однобайтовых локали Perl, как правило, использует правила локали для кодов символов, которые могут поместиться в один байт, и правила Unicode для тех, которые не могут (хотя это не применяется повсеместно, см. примечание в конце этого раздела). Это предотвращает многие проблемы в локалях, которые не являются UTF-8. Предположим, что локаль — ISO8859-7, греческая. Символ в 0xD7 там — большая буква хи. Но в локали ISO8859-1, Latin1, это знак умножения. Позиксный регулярный выражения символ класса [[: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. Используйте вместо этого позиксовые классы символов.
Ещё одна проблема с этим подходом заключается в том, что операции, пересекающие границу между одним и несколькими байтами, не определены надлежащим образом и поэтому запрещены. (Эта граница находится между кодовыми точками 255/256.) Например, при переводе в нижний регистр LATIN CAPITAL LETTER Y WITH DIAERESIS (U+0178) должно получиться LATIN SMALL LETTER Y WITH DIAERESIS (U+00FF). Но в греческой локали, например, нет символа с 0xFF, и Perl не знает, что этот символ на самом деле должен представлять. Поэтому он запрещает операцию. В этом режиме строчная форма 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.)
Примечание: Политика использования правил локали для кодовых точек, которые могут поместиться в байт, и правил Юникода для тех, которые не могут, не применяется однообразно. До версии 5.12 она была несколько произвольной; в версии 5.12 она применялась довольно последовательно для сопоставления с регулярными выражениями, за исключением заключённых в квадратные скобки классов символов; в версии 5.14 она была расширена на все соответствия с регулярными выражениями; а в версии 5.16 на операции преобразования регистра, такие как \L и uc(). Для сортировки в выпусках до настоящего времени вызывается функция strxfrm() системы, и что бы она ни делала, это и есть результат. Начиная с версии 5.26, исправлены различные ошибки в способе использования Perl этой функции.
ОШИБКИ
Сортировка строк, содержащих встроенные символы NUL
Символы NUL будут сортироваться так же, как наименьший управляющий символ сортировки, или к "\001" в маловероятном случае, если в локали вообще нет управляющих символов. В тех случаях, когда строки не содержат этот не-NUL управляющий символ, результаты будут правильными, и во многих локалях этот управляющий символ, каким бы он ни был, встречается редко. Но есть случаи, когда NUL должен сортироваться раньше этого управляющего символа, но этого не происходит. Если две строки сортируются идентично, то та, которая содержит NUL, будет отсортирована раньше. До версии 5.26 таких ошибок было больше.
Многопоточность
Код XS или библиотеки на языке C, вызываемые из него и использующие системную функцию setlocale(3) (за исключением Windows), вероятно, не будут работать из многопоточного приложения без изменений. См. "Locale-aware XS code" в perlxs.
Модуль XS, зависящий от локали, мог быть написан при предположении, что он никогда не будет вызван в многопоточной среде, и поэтому использует другие не зависящие от локали конструкции, которые не являются безопасными для многопоточности. См. "Thread-aware system interfaces" в perlxs.
POSIX не определяет способ получения имени текущей локали на поток. Некоторые системы, такие как Darwin и NetBSD, реализуют функцию querylocale(3) для этого. На системах, не являющихся 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 Джаррко Хьетаниеми, сильно изменённый Домиником Данлопом, при поддержке perl5-porters. Проза немного переработана Томом Кристиансеном, и теперь поддерживается разработчиками 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.30.3/perllocale