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 не поддерживает другие многобайтовые локали, такие как те, которые предназначены для восточноазиатских языков.
К сожалению, есть довольно много недостатков в проектировании (и часто в реализациях) локалей. Юникод был изобретен (см. perlunitut для введения в него), отчасти для решения этих недостатков проектирования, и в наши дни существует ряд «UTF-8 локалей», основанных на Юникоде. Это локали, кодировка символов которых — Юникод, закодированный в UTF-8. Начиная с версии 5.20, Perl полностью поддерживает UTF-8 локали, за исключением сортировки и сравнения строк, например lt и ge. Начиная с версии 5.26, Perl может обрабатывать их также, но это зависит от реализации платформы. Однако для более ранних выпусков или для лучшего контроля используйте Unicode::Collate. Фактически, есть два немного разных типа UTF-8 локалей: один для тюркских языков и другой для всех остальных.
Начиная с Perl v5.30, Perl определяет тюркские локали по их поведению и бесшовно обрабатывает оба типа; ранее поддерживался только не-тюркский. Название локали игнорируется, если ваша система имеет локаль tr_TR.UTF-8, и она не ведет себя как тюркская локаль, perl будет обрабатывать ее как не-тюркскую.
Perl продолжает поддерживать и старые локали, не являющиеся UTF-8. В настоящее время нет UTF-8 локалей для платформ EBCDIC.
(Unicode также создает CLDR, «Центральный репозиторий данных локалей» http://cldr.unicode.org/, который содержит больше типов информации, чем доступно в системе локалей POSIX. На момент написания этой статьи не было модуля CPAN, который предоставлял бы доступ к этим данным в формате XML. Однако возможно вычислить данные локали POSIX из них, и в более ранних версиях CLDR эти данные уже были извлечены для вас как UTF-8 локали http://unicode.org/Public/cldr/2.0.1/.)
ЧТО ТАКОЕ ЛОКАЛЬ
Локаль — это набор данных, описывающий различные аспекты того, как различные сообщества в мире классифицируют свой мир. Эти категории разбиваются на следующие типы (некоторые из которых содержат краткое примечание здесь):
-
Категория
LC_NUMERIC: Форматирование чисел -
Это указывает, как числа должны быть отформатированы для удобства чтения, например, символ, используемый в качестве десятичной точки.
-
Категория
LC_MONETARY: Форматирование денежных сумм -
Категория
LC_TIME: Форматирование даты/времени -
Категория
LC_MESSAGES: Сообщения об ошибках и другие сообщения -
Это используется самим Perl только для доступа к сообщениям об ошибках операционной системы с помощью
$!и$^E. -
Категория
LC_COLLATE: Сортировка -
Это указывает порядок букв для сравнения и сортировки. Например, в латинском алфавите "b" обычно следует за "a".
-
Категория
LC_CTYPE: Типы символов -
Это указывает, например, является ли символ заглавной буквой.
- Другие категории
-
На некоторых платформах есть другие категории, связанные с такими вещами, как единицы измерения и размеры бумаги. Ни одна из них не используется напрямую Perl, но внешние операции, с которыми взаимодействует Perl, могут их использовать. См. "Не входит в сферу действия "use locale"" ниже.
Более подробные сведения о категориях, используемых Perl, приведены ниже в "КАТЕГОРИИ ЛОКАЛЕЙ".
Вместе эти категории в значительной степени позволяют настроить одну программу для работы во многих разных местах. Но есть недостатки, поэтому продолжайте читать.
ПОДГОТОВКА К ИСПОЛЬЗОВАНИЮ ЛОКАЛЕЙ
Сам Perl (вне модуля POSIX) не будет использовать локали, если их не запросить явно (но обратите внимание, что Perl может взаимодействовать с кодом, который их использует). Даже если такой запрос есть, для правильной работы все из следующего должно быть истинным:
-
Ваша операционная система должна поддерживать систему локалей. Если да, то функция
setlocale()должна быть задокументирована в её библиотеке C. -
Определения используемых вами локалей должны быть установлены. Вы или ваш системный администратор должны убедиться в этом. Доступные локали, расположение, в котором они хранятся, и способ их установки различаются в разных системах. Некоторые системы предоставляют только несколько жёстко заданных локалей и не позволяют добавлять больше. Другие позволяют добавить "готовые" локали, предоставляемые поставщиком системы. Другие позволяют вам или системному администратору определять и добавлять произвольные локали. (Возможно, вам придется попросить вашего поставщика предоставить готовые локали, которые не поставляются с вашей операционной системой). Обратитесь к документации вашей системы для получения дополнительных разъяснений.
-
Perl должен считать, что система локалей поддерживается. Если это так,
perl -V:d_setlocaleскажет, что значениеd_setlocaleравноdefine.
Если вы хотите, чтобы приложение Perl обрабатывало и представляло ваши данные в соответствии с конкретной локалью, код приложения должен включать предикат use locale (см. "Предикат "use locale"") по мере необходимости, и по крайней мере одно из следующих утверждений должно быть истинным:
-
Переменные среды, определяющие локаль (см. "СРЕДА") должны быть правильно настроены во время запуска приложения, либо вами, либо пользователем, настроившим вашу учётную запись системы; или
-
Приложение должно установить свою собственную локаль, используя метод, описанный в "Функции setlocale".
Использование локалей
Директива "use locale"
Начиная с Perl 5.28, данную директиву можно использовать в многопоточных приложениях на системах, поддерживающих потокобезопасную работу с локалью. Применяются некоторые ограничения, см. "Многопоточные" ниже. На системах без этой возможности или в более ранних версиях Perl, НЕ используйте эту директиву в скриптах с активными множественными потоками. В этих случаях локаль не локальна для одного потока. Другой поток может изменить локаль в любой момент, что может привести как минимум к тому, что данный поток работает в локали, в которой он не ожидает находиться. На некоторых платформах также могут возникать сегментоошибки. Изменение локали необязательно должно быть явным; некоторые операции сами по себе заставляют Perl изменить локаль. Вы уязвимы просто из-за выполнения "use locale".
По умолчанию сам Perl (вне модуля POSIX) игнорирует текущую локаль. Директива use locale сообщает Perl использовать текущую локаль для некоторых операций. Начиная с версии 5.16, для этой директивы доступны необязательные параметры, описанные ниже, которые ограничивают, на какие операции она влияет.
Текущая локаль устанавливается во время выполнения функцией setlocale(), описанной ниже. Если эта функция ещё не была вызвана в ходе выполнения программы, текущая локаль — та, которая была определена переменными среды "СРЕДА", действующими в начале программы. Если действительных переменных среды нет, текущая локаль — та, что установлена по умолчанию в системе. В системах POSIX это, скорее всего, но не обязательно, локаль "C". В Windows по умолчанию она устанавливается с помощью Control Panel->Regional and Language Options (или её текущего эквивалента).
Операции, на которые влияет локаль:
-
Не в рамках действия директивы
"use locale" -
Только определённые операции (все исходящие за пределами Perl) должны затрагиваться, как указано ниже:
-
Текущая локаль используется при выходе за пределы Perl с операциями, такими как system() или qx//, если эти операции чувствительны к локали.
-
Также Perl предоставляет доступ к различным функциям библиотеки C через модуль POSIX. Некоторые из этих функций всегда зависят от текущей локали. Например,
POSIX::strftime()используетLC_TIME;POSIX::strtod()используетLC_NUMERIC;POSIX::strcoll()иPOSIX::strxfrm()используютLC_COLLATE. Все такие функции будут вести себя в соответствии с текущей базовой локалью, даже если эта локаль не экспонирована в пространство Perl.Это также относится к I18N::Langinfo.
-
Модули XS для всех категорий, кроме
LC_NUMERICполучают базовую локаль, и поэтому все вызовы функций библиотеки C, которые они делают, будут использовать эту базовую локаль. Более подробное обсуждение см. в "ЗАМЕЧАНИЯ" в perlxs.
Обратите внимание, что все программы на C (включая интерпретатор perl, написанный на C) всегда имеют базовую локаль. Эта локаль — локаль "C", если её не изменить вызовом setlocale(). При запуске Perl он меняет базовую локаль на указанную в "СРЕДЕ". При использовании модуля POSIX или написании кода XS важно помнить, что базовая локаль может быть другой, чем "C", даже если программа явно её не изменила.
-
-
Длительные эффекты директивы
use locale -
Некоторые операции Perl, настроенные в рамках действия директивы
use locale, сохраняют этот эффект даже вне её области действия. К ним относятся:-
Формат вывода функции write() определяется более ранней декларацией формата ("format" в perlfunc), поэтому то, влияет ли вывод на локаль, определяется тем, находится ли директива
format()внутри области действия директивыuse locale, а не тем, находится ли директиваwrite()в ней. -
Шаблоны регулярных выражений могут быть скомпилированы с помощью qr// с отложенным фактическим сопоставлением на более поздний этап. Опять же, то, будет ли сопоставление выполняться в рамках действия директивы
use locale, определяет поведение соответствия, а не то, выполняются ли соответствия внутри такой области или нет.
-
-
В рамках директивы
"use locale"; -
-
Все вышеперечисленные операции
-
Декларации форматов ("format" в perlfunc) и, следовательно, все последующие
write()используютLC_NUMERIC. -
Преобразование в строку и вывод используют
LC_NUMERIC. К ним относятся результатыprint(),printf(),say(), иsprintf(). -
Операторы сравнения (
lt,le,cmp,ge, иgt) используютLC_COLLATE.sort()также затронут, если используется без явной функции сравнения, так как по умолчанию он используетcmp.Примечание:
eqиneне зависят от локали: они всегда выполняют посимвольное сравнение своих скалярных операндов. Более того, еслиcmpобнаружит, что его операнды равны согласно порядку сортировки, указанному текущей локалью, он переходит к посимвольному сравнению и возвращает 0 (равны) только если операнды идентичны посимвольно. Если вы действительно хотите узнать, равны ли две строки, которыеeqиcmpмогут рассматривать по-разному, равны ли они с точки зрения сортировки по локали, см. обсуждение в "КатегорияLC_COLLATE: Сортировка". -
Функции регулярных выражений и изменения регистра (
uc(),lc(),ucfirst(), иlcfirst()) используютLC_CTYPE -
Переменные
$!(и её синонимы$ERRNOи$OS_ERROR) и$^E> (и её синоним$EXTENDED_OS_ERROR), когда используются как строки, используютLC_MESSAGES.
-
Исходное поведение восстанавливается с помощью директивы no locale или при достижении конца блока, содержащего use locale. Обратите внимание, что вызовы use locale могут быть вложены, и то, что действует внутри вложенного блока, вернётся к правилам внешнего блока по завершении внутреннего блока.
Результат любой операции, использующей информацию о локали, заражён (если ваш perl поддерживает проверку заражения), так как локаль может быть ненадежной. См. "БЕЗОПАСНОСТЬ".
Начиная с 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 эта функция становится бесполезной после запуска любого потока. Таким образом, в этой системе вы можете настроить локаль до создания любых потоков, и эта локаль будет действовать для всей программы.
В противном случае вы можете переключать локали так часто, как пожелаете, во время выполнения с помощью функции 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: изменения среды, внесенные приложением после запуска, могут или не могут быть замечены в зависимости от используемой С-библиотеки вашей системы.
Обратите внимание, что когда используется форма 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 приведена в "Локализуемые код XS" в perlxs.
Поиск языковых стандартов
Для языковых стандартов, доступных на вашей системе, также обратитесь к setlocale(3), чтобы увидеть, приводит ли это к списку доступных языковых стандартов (ищите раздел SEE ALSO). Если это не сработает, попробуйте следующие команды:
locale -a
nlsinfo
ls /usr/lib/nls/loc
ls /usr/lib/locale
ls /usr/lib/nls
ls /usr/share/locale и посмотрите, выводят ли они что-то подобное
en_US.ISO8859-1 de_DE.ISO8859-1 ru_RU.ISO8859-5
en_US.iso88591 de_DE.iso88591 ru_RU.iso88595
en_US de_DE ru_RU
en de ru
english german russian
english.iso88591 german.iso88591 russian.iso88595
english.roman8 russian.koi8r К сожалению, хотя интерфейс вызова для setlocale() стандартизирован, имена языковых стандартов и каталоги, где хранятся настройки, нет. Базовая форма имени — язык_территория.кодовая_страница, но последние части после язык не всегда присутствуют. Язык и страна обычно берутся из стандартов ISO 3166 и ISO 639, сокращений из двух букв для стран и языков мира соответственно. Часть кодовая_страница часто упоминает набор символов ISO 8859, наборы символов на латинице. Например, ISO 8859-1 — это так называемый «западноевропейский набор символов», который можно использовать для кодирования большинства западноевропейских языков. Опять же, существуют разные способы записи даже имени этого стандарта. К сожалению.
Два особых языковых стандарта заслуживают особого упоминания: «C» и «POSIX». В настоящее время они фактически являются одним и тем же языковым стандартом: различие заключается главным образом в том, что первый определяется стандартом C, а второй — стандартом POSIX. Они определяют языковой стандарт по умолчанию, в котором каждая программа запускается в отсутствие информации о языковом стандарте в её среде. (Если хотите, это базовый языковой стандарт по умолчанию.) Его язык — (американский) английский, а набор символов — ASCII или, реже, его супермножество (такое как «DEC 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() саму и три константы, которые будут использоваться в качестве аргументов для %%%CODE_BLOCK_175%%: константу для сокращённого первого дня недели (нумерация начинается с воскресенья = 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. Это определяет представление приложения о том, какие символы являются буквенными, цифровыми, знаками препинания и т. д. Это влияет на метанотацию регулярных выражений 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.
Начиная с версии 5.20, Perl поддерживает локаль UTF-8 для LC_CTYPE, но в противном случае Perl поддерживает только однобайтовые локали, такие как серии ISO 8859. Это означает, что локали с широким набором символов, например, для азиатских языков, не поддерживаются должным образом. Использование таких локалей может привести к аварийному завершению работы. Если платформа имеет возможность для Perl обнаружить такую локаль, начиная с версии Perl 5.22, Perl будет выводить предупреждение, по умолчанию включенное, используя категорию предупреждений locale, всякий раз, когда такая локаль переключается. Поддержка локали UTF-8 фактически является надмножеством локалей POSIX, потому что она фактически представляет полное поведение Unicode, как будто никакой LC_CTYPE локали вообще не было (за исключением загрязнения; см. "БЕЗОПАСНОСТЬ"). Локали POSIX, даже UTF-8, лишены определенных концепций в Unicode, таких как идея о том, что изменение регистра символа может расшириться до большего, чем одного символа. Perl в локали UTF-8 предоставит вам это расширение. До версии 5.20 Perl на некоторых платформах обрабатывал локаль UTF-8 как локаль ISO 8859-1 с некоторыми ограничениями, а на других платформах - как локаль "C". Для выпусков v5.16 и v5.18, use locale 'not_characters можно было использовать в качестве обходного решения для этого (см. "Unicode и UTF-8").
Обратите внимание, что некоторые вещи не зависят от текущей локали. Любой буквенный символ является родным символом для данной платформы. Следовательно, 'A' означает символ с кодовым значением 65 на платформах ASCII и 193 на платформах EBCDIC. Это может или не может быть 'A' в текущей локали, если эта локаль вообще имеет 'A'. Аналогично, все последовательности escape для определенных символов, \n например, всегда означают родной символ платформы. Это означает, что, например, \N в регулярных выражениях (каждый символ, кроме новой строки) работает с набором символов платформы.
Начиная с версии 5.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, а также операционную систему и ее утилиты. Обратите особое внимание на то, что строковое значение $! и сообщения об ошибках, выдаваемые внешними утилитами, могут изменяться в зависимости от 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 и не имеют сворачиваний по правилам 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 используется системная локаль по умолчанию. Если всё остальное не работает, что-то серьёзно сломано, но 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— переменная среды локали «всеобъемлющего» типа. Если она установлена, она используется в качестве последней надежды после общей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:Сортировка устаревшая
В версиях Perl до 5.004 модуль библиотеки I18N::Collate позволял сортировку по локали. Этот модуль сейчас несколько устарел и следует избегать в новых приложениях. Функциональность LC_COLLATE теперь интегрирована в язык Perl: теперь можно использовать данные скаляров, специфичные для локали, совершенно нормально с use locale, поэтому больше нет необходимости работать со скалярными ссылками I18N::Collate.
Влияние скорости сортировки и использования памяти
Сравнение и сортировка по локали обычно медленнее, чем по умолчанию; наблюдалось замедление в два-четыре раза. Она также будет потреблять больше памяти: после того, как переменная Perl scalar участвовала в любой операции сравнения строк или сортировки, подчиняющейся правилам сортировки локали, она займёт в 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, в 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, вы получите менее идеальное поведение, описанное ниже, которое вы получаете с 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 в этом случае — заглавная буква Chi. Но в локали 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 для прагмы locale (кроме ошибок поставщика в несимвольных частях). Если у вас нет 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 и FreeBSD, реализуют функцию 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 был сильно изменён Dominicom Dunlop, при поддержке perl5-porters. Текст был переработан Томом Кристиансеном, и теперь поддерживается Perl 5 porters.
© 1993–2023 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.38.0/perllocale