Spec-Zone.ru › Perl 5.34

perllocale

СОДЕРЖАНИЕ

  • ИМЯ
  • ОПИСАНИЕ
  • ЧТО ТАКОЕ ЛОКАЛЬ
  • ПОДГОТОВКА К ИСПОЛЬЗОВАНИЮ ЛОКАЛЕЙ
  • ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ
    • Предикат "use locale"
    • Функция setlocale
    • Многопоточная работа
    • Поиск локалей
    • ПРОБЛЕМЫ С ЛОКАЛЯМИ
    • Проверка на неисправные локали
    • Временное исправление проблем с локали
    • Постоянное исправление проблем с локали
    • Постоянное исправление конфигурации локалей вашей системы
    • Исправление конфигурации системной локали
    • Функция localeconv
    • I18N::Langinfo
  • КАТЕГОРИИ ЛОКАЛЕЙ
    • Категория LC_COLLATE: Сортировка: Сравнение текста и сортировка
    • Категория LC_CTYPE: Типы символов
    • Категория LC_NUMERIC: Форматирование чисел
    • Категория LC_MONETARY: Форматирование денежных сумм
    • Категория LC_TIME: Представление времени
    • Другие категории
  • БЕЗОПАСНОСТЬ
  • СРЕДА
    • Примеры
  • ПРИМЕЧАНИЯ
    • String eval и LC_NUMERIC
    • Обратная совместимость
    • I18N:Collate устарел
    • Воздействие на скорость сортировки и использование памяти
    • Свободно доступные определения локалей
    • I18n и l10n
    • Несовершенный стандарт
  • Unicode и UTF-8
  • ОШИБКИ
    • Сортировка строк, содержащих вставленные символы NUL
    • Многопоточная
    • Неисправные системы
  • СМОТРИТЕ ТАКЖЕ
  • ИСТОРИЯ

ИМЯ

perllocale — Обработка локалей Perl (международная и локализованная версия)

ОПИСАНИЕ

Вначале был ASCII, «Американский стандартный код обмена информацией», который довольно хорошо работает для американцев с их английским алфавитом и валютой в долларах. Но он работает не так хорошо даже для других англоговорящих, которые могут использовать другие валюты, такие как фунт стерлингов (так как символ этой валюты отсутствует в ASCII); и он совершенно неприемлем для многих тысяч других языков мира.

Для решения этих недостатков была изобретена концепция локалей (формально ISO C, XPG4, POSIX 1.c «система локалей»). И приложения пишутся и используются, используя механизм локалей. Процесс учета предпочтений пользователей в этом типе вопросов называется **интернационализацией** (часто сокращенно **i18n**); предоставление такому приложению набора конкретных предпочтений известно как **локализация** (**l10n**).

Perl был расширен для поддержки определенных типов локалей, доступных в системе локалей. Это контролируется в приложении с помощью одного предикатов, одного вызова функции и нескольких переменных среды.

Perl поддерживает однобайтовые локали, которые являются надмножествами ASCII, такие как ISO 8859, и одну многобайтовую локаль типа UTF-8, описанную в следующем абзаце. Perl не поддерживает другие многобайтовые локали, такие как те, которые используются для восточноазиатских языков.

К сожалению, в структуре (и часто в реализации) локалей есть довольно много недостатков. Unicode был изобретен (см. perlunitut для введения в него), отчасти для решения этих недостатков дизайна, и сегодня существует ряд «UTF-8 локалей», основанных на Unicode. Это локали, в которых набором символов является Unicode, закодированный в UTF-8. Начиная с версии 5.20, Perl полностью поддерживает UTF-8 локали, за исключением сортировки и сравнения строк, таких как lt и ge. Начиная с v5.26, Perl также может обрабатывать их достаточно хорошо, в зависимости от реализации платформы. Однако для более ранних версий или для лучшего контроля используйте Unicode::Collate. На самом деле существует два немного разных типа UTF-8 локалей: один для тюркских языков и один для всех остальных.

Начиная с Perl v5.30, Perl обнаруживает тюркские локали по их поведению и бесшовно обрабатывает оба типа; ранее поддерживался только не-тюркский тип. Если ваша система имеет локаль tr_TR.UTF-8, и она не ведет себя как тюркская локаль, Perl будет обрабатывать её как не-тюркскую локаль.

Perl продолжает поддерживать старые не-UTF-8 локали. В настоящее время нет UTF-8 локалей для платформ EBCDIC.

(Unicode также создает CLDR, «Общий репозиторий данных локалей», http://cldr.unicode.org/, который включает больше типов информации, чем доступно в системе POSIX локалей. На момент написания этой статьи не было модуля CPAN, предоставляющего доступ к этим данным в формате XML. Однако возможно вычислить данные POSIX локали из них, и в более ранних версиях CLDR эти данные уже были извлечены для вас в виде UTF-8 локалей http://unicode.org/Public/cldr/2.0.1/.)

ЧТО ТАКОЕ ЛОКАЛЬ

Локаль — это набор данных, описывающий различные аспекты того, как различные сообщества в мире классифицируют свой мир. Эти категории разбиты на следующие типы (некоторые из которых содержат краткое примечание здесь):

Категория LC_NUMERIC: Форматирование чисел

Это указывает, как числа должны быть отформатированы для удобства чтения человеком, например, символ, используемый в качестве десятичной точки.

Категория LC_MONETARY: Форматирование денежных сумм
Категория LC_TIME: Форматирование даты и времени
Категория LC_MESSAGES: Сообщения об ошибках и другие сообщения

Это используется самим Perl только для доступа к сообщениям об ошибках операционной системы через $! и $^E.

Категория LC_COLLATE: Сортировка

Это указывает порядок букв для сравнения и сортировки. Например, в латинских алфавитах «b» обычно следует за «a».

Категория LC_CTYPE: Типы символов

Это указывает, например, является ли символ заглавной буквой.

Другие категории

Некоторые платформы имеют другие категории, связанные с такими вещами, как единицы измерения и размеры бумаги. Ни одна из них не используется непосредственно Perl, но внешние операции, с которыми взаимодействует Perl, могут использовать их. См. "Не входит в область применения "use locale"" ниже.

Дополнительные сведения о категориях, используемых Perl, приведены ниже в разделе "КАТЕГОРИИ ЛОКАЛЕЙ".

Вместе эти категории значительно способствуют настройке одного приложения для работы во многих разных местах. Но существуют недостатки, поэтому продолжайте чтение.

ПОДГОТОВКА К ИСПОЛЬЗОВАНИЮ ЛОКАЛЕЙ

Сам Perl (вне модуля POSIX) не будет использовать локали, если их не запросить явно (но обратите внимание, что Perl может взаимодействовать с кодом, который их использует). Даже если такой запрос есть, для корректной работы должны выполняться **все** следующие условия:

  • Ваша операционная система должна поддерживать систему локалей. Если это так, вы должны обнаружить, что функция setlocale() является документированной частью её C-библиотеки.

  • Определения локалей, которые вы используете, должны быть установлены. Вы или ваш системный администратор должны убедиться, что это так. Доступные локали, место их хранения и способ установки различаются в разных системах. Некоторые системы предоставляют только несколько жестко запрограммированных локалей и не позволяют добавлять больше. Другие позволяют добавлять «готовые» локали, предоставленные поставщиком системы. В некоторых случаях вы или системный администратор можете определять и добавлять произвольные локали. (Возможно, вам нужно попросить вашего поставщика предоставить готовые локали, которые не поставляются с вашей операционной системой.) Обратитесь к документации вашей системы для получения дополнительной информации.

  • Perl должен считать, что система локалей поддерживается. Если это так, perl -V:d_setlocale скажет, что значение для d_setlocale равно define.

Если вы хотите, чтобы приложение Perl обрабатывало и представляло ваши данные в соответствии с конкретной локалью, код приложения должен содержать предикат use locale (см. "Предикат "use locale""), где это уместно, и **хотя бы одно** из следующих условий должно быть истинным:

  1. Переменные среды, определяющие локаль (см. "СРЕДА") должны быть корректно настроены при запуске приложения, либо вами, либо тем, кто настраивал вашу учётную запись системы; или

  2. Приложение должно установить свою локаль, используя метод, описанный в "Функция setlocale".

ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ

Директива "use locale"

Начиная с Perl 5.28, эту директиву можно использовать в многопоточных приложениях на системах, поддерживающих потокобезопасные локали. Применяются некоторые ограничения, см. "Многопоточные" ниже. На системах без этой возможности или в более ранних версиях Perl НЕ используйте эту директиву в скриптах, в которых активны несколько потоков. В этих случаях локаль не является локальной для одного потока. Другой поток может изменить локаль в любой момент, что, как минимум, может привести к тому, что данный поток работает в локали, которой он не ожидал. На некоторых платформах также могут возникать ошибки сегментации. Изменение локали необязательно должно быть явным; некоторые операции заставляют Perl изменять локаль самостоятельно. Вы подвержены риску просто выполнив "use locale".

По умолчанию сам Perl (вне модуля POSIX) игнорирует текущую локаль. Директива use locale сообщает Perl использовать текущую локаль для некоторых операций. Начиная с версии 5.16, для этой директивы доступны необязательные параметры, описанные ниже, которые ограничивают, какие операции на нее влияют.

Текущая локаль устанавливается во время выполнения функцией setlocale(), описанной ниже. Если эта функция ещё не была вызвана в ходе выполнения программы, текущая локаль определяется "СРЕДОЙ", которая была в силе при запуске программы. Если нет действительной среды, текущей локалью является локаль, заданная по умолчанию системой. На системах POSIX это, вероятно, но не обязательно, локаль "C". В Windows локаль по умолчанию устанавливается через Control Panel->Regional and Language Options компьютера (или её текущий эквивалент).

Операции, на которые влияет локаль:

Не в области действия "use locale"

Только некоторые операции (все происходящие вне Perl) должны подвергаться влиянию, как указано ниже:

  • Текущая локаль используется при выходе за пределы Perl с операциями, такими как system() или qx//, если эти операции чувствительны к локали.

  • Также Perl предоставляет доступ к различным функциям библиотеки C через модуль POSIX. Некоторые из этих функций всегда зависят от текущей локали. Например, POSIX::strftime() использует LC_TIME; POSIX::strtod() использует LC_NUMERIC; POSIX::strcoll() и POSIX::strxfrm() используют LC_COLLATE. Все такие функции будут вести себя в соответствии с текущей локалью, даже если эта локаль не раскрыта для Perl.

    Это также относится к I18N::Langinfo.

  • Модули XS для всех категорий, кроме LC_NUMERIC получают базовую локаль, и, следовательно, любые функции библиотеки C, которые они вызывают, будут использовать эту базовую локаль. Более подробное обсуждение см. в "ПРИМЕЧАНИЯ" в perlxs.

Обратите внимание, что все программы на C (включая интерпретатор Perl, написанный на C) всегда имеют базовую локаль. Эта локаль является локалью "C", если не изменена вызовом setlocale(). При запуске Perl он изменяет базовую локаль на ту, которая указана в "СРЕДЕ". При использовании модуля POSIX или написании кода XS важно помнить, что базовая локаль может быть чем-то другим, кроме "C", даже если программа явно не изменила её.

Остаточные эффекты use locale

Некоторые операции Perl, которые настраиваются в рамках области действия use locale, сохраняют этот эффект даже за её пределами. К ним относятся:

  • Формат вывода функции write() определяется предыдущим объявлением формата ("формат" в perlfunc), поэтому то, влияет ли вывод на локаль, определяется тем, находится ли format() в области действия use locale, а не тем, находится ли write() в такой области.

  • Шаблоны регулярных выражений могут быть скомпилированы с помощью qr// с отложенным фактическим сопоставлением на более поздний срок. Опять же, то, скомпилировано ли сопоставление в пределах области действия use locale, определяет поведение сопоставления, а не то, выполняется ли сопоставление в такой области или нет.

В рамках "use locale";
  • Все вышеперечисленные операции

  • Объявления форматов ("формат" в perlfunc) и, следовательно, все последующие write()ы используют LC_NUMERIC.

  • Преобразование строк в строки и вывод используют LC_NUMERIC. К ним относятся результаты print(), printf(), say(), и sprintf().

  • Операторы сравнения (lt, le, cmp, ge, и gt), используют LC_COLLATE. sort() также затронуто, если используется без явной функции сравнения, поскольку оно по умолчанию использует cmp.

    Примечание: eq и ne не затрагиваются локалью: они всегда выполняют посимвольное сравнение своих скалярных операндов. Более того, если cmp обнаружит, что его операнды равны согласно порядку сортировки, указанному текущей локалью, оно переходит к посимвольному сравнению и возвращает 0 (равно) только если операнды идентичны посимвольно. Если вы действительно хотите узнать, являются ли две строки — которые eq и cmp могут рассматривать по-разному — равными с точки зрения сортировки в локали, см. обсуждение в "Категория LC_COLLATE: Сортировка".

  • Регулярные выражения и функции изменения регистра (uc(), lc(), ucfirst(), и lcfirst()), используют LC_CTYPE

  • Переменные $! (и её синонимы $ERRNO и $OS_ERROR), и $^E (и её синоним $EXTENDED_OS_ERROR), при использовании в виде строк, используют LC_MESSAGES.

Исходное поведение восстанавливается с помощью директивы no locale или при достижении конца блока, содержащего use locale. Обратите внимание, что вызовы use locale могут быть вложены, и то, что действует внутри внутреннего блока, вернётся к правилам внешнего блока по окончании внутреннего блока.

Строковый результат любой операции, которая использует информацию о локали, является заражённым, так как возможно, что локаль ненадёжна. См. "БЕЗОПАСНОСТЬ".

Начиная с Perl v5.16 в очень ограниченном виде, и более широко в v5.22, вы можете ограничить, какие категории включены в данной директиве, добавив параметры. Например,

use locale qw(:ctype :numeric);

включает осведомлённость о локали в пределах своей области действия только для тех операций (перечисленных выше), которые зависят от LC_CTYPE и LC_NUMERIC.

Возможные категории: :collate, :ctype, :messages, :monetary, :numeric, :time, и псевдокатегория :characters (описанная ниже).

Таким образом, вы можете сказать

use locale ':messages';

и только $! и $^E будут учитываться локали. Всё остальное не будет затронуто.

Так как Perl сейчас не делает ничего с категорией LC_MONETARY, указание :monetary фактически ничего не меняет. Некоторые системы имеют другие категории, такие как LC_PAPER, но Perl также ничего с ними не делает, и нет способа указать их в аргументах этой директивы.

Вы также можете легко сказать, чтобы использовать все категории, кроме одной, например,

use locale ':!ctype';
use locale ':not_ctype';

оба из которых означают включение осведомлённости о локали всех категорий, кроме LC_CTYPE. В отрицательной форме может быть указан только один аргумент категории.

До версии 5.22 доступен только один вариант директивы с аргументами:

use locale ':not_characters';

(и вам нужно сказать not_; вы не можете использовать форму с восклицательным знаком !). Эта псевдокатегория является сокращением для указания :collate и :ctype. Следовательно, в отрицательной форме она почти то же самое, что и

use locale qw(:messages :monetary :numeric :time);

Мы используем термин "почти", потому что :not_characters также включает use feature 'unicode_strings' в пределах своей области действия. Этот вариант менее полезен в v5.20 и более поздних версиях и подробно описан в "Unicode и UTF-8", но коротко: он сообщает Perl не использовать символьные части определения локали, то есть категории LC_CTYPE и LC_COLLATE. Вместо этого он будет использовать родную кодировку символов (расширенную с помощью Unicode). При использовании этого параметра вы сами должны обеспечить преобразование внешней кодировки символов в родную/Unicode (которая уже будет такой, если это одна из всё более популярных UTF-8 локалей). Для этого есть удобные способы, описанные в "Unicode и UTF-8".

Функция setlocale

ВНИМАНИЕ! До Perl 5.28 или на системах, которые не поддерживают потокобезопасные операции с локалью, НЕ используйте эту функцию в потоке. Локаль будет меняться во всех остальных потоках одновременно, и если ваш поток будет приостановлен операционной системой, а другой запущен, этот поток не получит ожидаемую локаль. На некоторых платформах может возникнуть гонка, приводящая к ошибкам сегментации, если две нити почти одновременно вызывают эту функцию. Это предупреждение не относится к однопоточным сборкам или к Perl, где ${^SAFE_LOCALES} существует и не равно нулю; а именно Perl 5.28 и более поздние однопоточные или скомпилированные для потокобезопасной локали.

Вы можете изменять локали так часто, как вам нужно, во время выполнения с помощью функции POSIX::setlocale():

# Import locale-handling tool set from POSIX module.
# This example uses: setlocale -- the function call
#                    LC_CTYPE -- explained below
# (Showing the testing for success/failure of operations is
# omitted in these examples to avoid distracting from the main
# point)

use POSIX qw(locale_h);
use locale;
my $old_locale;

# query and save the old locale
$old_locale = setlocale(LC_CTYPE);

setlocale(LC_CTYPE, "fr_CA.ISO8859-1");
# LC_CTYPE now in locale "French, Canada, codeset ISO 8859-1"

setlocale(LC_CTYPE, "");
# LC_CTYPE now reset to the default defined by the
# LC_ALL/LC_CTYPE/LANG environment variables, or to the system
# default.  See below for documentation.

# restore the old locale
setlocale(LC_CTYPE, $old_locale);

Первый аргумент setlocale() задаёт категорию, второй — локаль. Категория указывает, к какой части обработки данных нужно применить локально-специфические правила. Названия категорий обсуждаются в "КАТЕГОРИИ ЛОКАЛЕЙ" и "СРЕДА". Локаль — имя набора параметров настройки, соответствующее определённой комбинации языка, страны или региона и кодировки. Подробнее о наименованиях локалей см. ниже: не все системы называют локали так, как показано в примере.

Если второй аргумент не указан, а категория отлична от LC_ALL, функция возвращает строку, содержащую имя текущей локали для данной категории. Вы можете использовать это значение во втором аргументе последующего вызова setlocale(), но на некоторых платформах эта строка неинформативна, и большинство людей не смогут определить, какой локаль она представляет.

Если второй аргумент не указан, а категория равна LC_ALL, результат зависит от реализации. Это может быть строка, содержащая конкатенированные имена локалей (разделитель также зависит от реализации), или одно имя локали. Для получения подробностей обратитесь к странице руководства setlocale(3).

Если второй аргумент задан и соответствует действительной локали, локаль для категории устанавливается на это значение, и функция возвращает текущее значение локали. Это значение можно использовать в ещё одном вызове setlocale(). (В некоторых реализациях возвращаемое значение может отличаться от заданного вами второго аргумента — считайте его псевдонимом заданного вами значения.)

Как показано в примере, если второй аргумент пустая строка, локаль категории возвращается к значению по умолчанию, определённому соответствующими переменными среды. В общем случае это значение возвращается к значению, действовавшему при запуске Perl: изменения в среде, внесённые приложением после запуска, могут или могут не быть замечены, в зависимости от вашей системы C-библиотеки.

Обратите внимание, что когда указана форма use locale, не включающая все категории, Perl игнорирует исключённые категории.

Если setlocale() по какой-либо причине завершается неудачно (например, при попытке установить неизвестную системе локаль), локаль для категории не изменяется, и функция возвращает undef.

Начиная с Perl 5.28, в многопоточных версиях Perl, скомпилированных на системах, поддерживающих многопоточные операции с локалью POSIX 2008, эта функция фактически не вызывает системную setlocale. Вместо этого для эмуляции функции setlocale используются многопоточные операции с локалью, но безопасным для многопоточности способом.

Вы можете всегда использовать многопоточные операции с локалью (если они доступны), перекомпилировав Perl с

-Accflags='-DUSE_THREAD_SAFE_LOCALE'

добавленной в вызов Configure.

Для получения дополнительной информации о категориях обратитесь к setlocale(3).

Многопоточная работа

Начиная с Perl 5.28, многопоточная работа с локалью поддерживается на системах, которые реализуют многопоточные операции с локалью POSIX 2008 или специфичные для Windows. Многие современные системы, такие как различные варианты Unix и Darwin, имеют эту возможность.

Вы можете определить, безопасны ли операции с локалью на вашей системе, посмотрев на доступную переменную-булево значение ${^SAFE_LOCALES}. Значение равно 1, если Perl не многопоточный или использует многопоточные операции с локалью.

Многопоточные операции поддерживаются в Windows, начиная с Visual Studio 2005, и на системах, совместимых с POSIX 2008. Некоторые платформы заявляют о поддержке POSIX 2008, но имеют нерабочие реализации, поэтому в файлах подсказок для компиляции на них отключается попытка использовать многопоточность. ${^SAFE_LOCALES} будет равно 0 на таких платформах.

Помните, что разработка многопоточного приложения не будет портирована на платформы, не имеющие встроенной поддержки многопоточных операций с локалью. На системах, которые её имеют, это поведение автоматически применяется для многопоточных версий Perl без дополнительных действий. Если по какой-то причине вы не хотите использовать эту возможность (возможно, поддержка POSIX 2008 нерабочая на вашей системе), вы можете вручную скомпилировать Perl с использованием старой, не многопоточной реализации, передав аргумент -Accflags='-DNO_THREAD_SAFE_LOCALE' в Configure. За исключением Windows, в некоторых ситуациях это будет продолжать использовать определённые функции POSIX 2008. Если они неисправны, вы можете передать следующее в Configure вместо или дополнительно: -Accflags='-DNO_POSIX_2008_LOCALE'. Это также предотвратит использование многопоточных локалей. ${^SAFE_LOCALES} будет равно 0 на системах, которые отключают многопоточные операции.

Обычно в не-многопоточных сборках используется традиционная setlocale(), а не многопоточные функции локали. Вы можете принудительно использовать их на системах, которые их поддерживают, добавив -Accflags='-DUSE_THREAD_SAFE_LOCALE' в Configure.

Изначальная программа запускается с использованием локали, указанной в среде, как описано в "СРЕДЕ". Все вновь созданные потоки запускаются со значением LC_ALL равным "C". Каждый поток может использовать POSIX::setlocale() для запроса или изменения своей локали в любое время без влияния на другие потоки. Все операции, зависящие от локали, автоматически используют локаль потока.

Это должно быть полностью прозрачно для любых приложений, написанных полностью на Perl (за исключением нескольких редко встречающихся случаев, указанных в разделе "Многопоточная обработка"). Информация для авторов модулей XS приведена в разделе "Локализованный код 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() и три константы, которые будут использоваться в качестве аргументов для langinfo(): константу для сокращенного первого дня недели (нумерация начинается с воскресенья = 1) и две другие константы для утвердительных и отрицательных ответов на вопрос «да/нет» в текущей локали.

use I18N::Langinfo qw(langinfo ABDAY_1 YESSTR NOSTR);

my ($abday_1, $yesstr, $nostr)
            = map { langinfo } qw(ABDAY_1 YESSTR NOSTR);

print "$abday_1? [$yesstr/$nostr] ";

Другими словами, в локали «C» (или английской) выше, вероятно, будет напечатано что-то вроде:

Sun? [yes/no]

См. I18N::Langinfo для получения дополнительной информации.

КАТЕГОРИИ ЛОКАЛЕЙ

В следующих подразделах описываются основные категории локалей. Помимо этого, некоторые комбинированные категории позволяют манипулировать более чем одной базовой категорией одновременно. См. "СРЕДА" для обсуждения этих категорий.

Категория LC_COLLATE: Сортировка: Сравнение текста и сортировка

В рамках use locale формы, включающей сортировку, Perl обращается к переменной среды LC_COLLATE для определения представлений приложения о сортировке (упорядочении) символов. Например, «b» следует за «a» в латинских алфавитах, но куда относятся «á» и «å»? И хотя «color» следует за «chocolate» по-английски, что насчёт традиционного испанского?

Следующие сортировки имеют смысл, и вы можете встретить любую из них, если "use locale".

A B C D E a b c d e
A a B b C c D d E e
a A b B c C d D e E
a b c d e A B C D E

Вот фрагмент кода, который показывает, какие символы «word» находятся в текущей локали, в порядке этой локали:

use locale;
print +(sort grep /\w/, map { chr } 0..255), "\n";

Сравните это с символами, которые вы видите, и их порядком, если вы явно укажете, что локали следует игнорировать:

no locale;
print +(sort grep /\w/, map { chr } 0..255), "\n";

Эта машинная сортировка (которую вы получаете, если use locale не появилась ранее в том же блоке) должна использоваться для сортировки необработанных двоичных данных, тогда как зависимая от локали сортировка первого примера полезна для естественного текста.

Как отмечено в "ИСПОЛЬЗОВАНИЕ ЛОКАЛЕЙ", cmp сравнивает в соответствии с текущей локалью сортировки, когда use locale активна, но переходит к посимвольному сравнению для строк, которые локаль считает равными. Вы можете использовать POSIX::strcoll() , если вы не хотите этого перехода:

use POSIX qw(strcoll);
$equal_in_locale =
    !strcoll("space and case ignored", "SpaceAndCaseIgnored");

$equal_in_locale будет истинно, если локаль сортировки задаёт порядком упорядочения, подобный словарю, который полностью игнорирует пробелы и сворачивает регистр.

Perl использует функции сортировки C библиотеки платформы strcoll() и strxfrm(). Это означает, что вы получаете то, что они предоставляют. На некоторых платформах эти функции хорошо работают с UTF-8 локалями, предоставляя разумную сортировку по умолчанию для кодовых точек, которые важны в этой локали. (И если они не работают хорошо, проблема может заключаться только в том, что определение локали неполно, поэтому может быть исправлена с помощью лучшего файла определения. Определения Unicode (см. "Свободно доступные определения локалей") предоставляют разумные определения сортировки локалей UTF-8.) Начиная с Perl v5.26, использование Perl этих функций стало более бесшовным. Это может быть достаточно для ваших потребностей. Для большего контроля и для обеспечения правильной сортировки строк, содержащих любые кодовые точки (а не только те, которые важны в локали), рекомендуется модуль Unicode::Collate.

В локалях, не являющихся UTF-8 (следовательно, однобайтовые), кодовые точки выше 0xFF технически недопустимы. Но если они присутствуют, начиная с версии 5.26, они будут отсортированы в ту же позицию, что и самая высокая допустимая кодовая точка. Это обычно даёт хорошие результаты, но порядок сортировки может быть искажён, если допустимая кодовая точка получает специальное обращение при формировании определённых последовательностей с другими символами, как определено в локали. Если две строки отсортированы одинаково, порядок кодовых точек используется в качестве разрывателя ничьей.

Если Perl обнаруживает проблемы с порядком сортировки локали, он возвращается к правилам сортировки без локали для этой локали.

Если у вас есть одна строка, которую вы хотите проверить на «равенство в локали» по отношению к нескольким другим, вы можете подумать, что можете получить немного эффективности, используя POSIX::strxfrm() в сочетании с eq:

use POSIX qw(strxfrm);
$xfrm_string = strxfrm("Mixed-case string");
print "locale collation ignores spaces\n"
    if $xfrm_string eq strxfrm("Mixed-casestring");
print "locale collation ignores hyphens\n"
    if $xfrm_string eq strxfrm("Mixedcase string");
print "locale collation ignores case\n"
    if $xfrm_string eq strxfrm("mixed-case string");

strxfrm() принимает строку и отображает её в преобразованную строку для использования в посимвольном сравнении с другими преобразованными строками во время сортировки. «Под капотом» операторы сравнения Perl, затрагиваемые локалью, вызывают strxfrm() для обоих операндов, затем выполняют посимвольное сравнение преобразованных строк. Явно вызвав strxfrm() и используя сравнение, не зависящее от локали, пример пытается сэкономить пару преобразований. Но на самом деле он ничего не экономит: магия Perl (см. "Магические переменные" в perlguts) создаёт преобразованную версию строки при первом её использовании в сравнении, а затем хранит эту версию на случай необходимости повторного использования. Переписанный пример простым способом с cmp выполняется примерно с той же скоростью. Он также справляется с нулевыми символами, встроенными в строки; если вы напрямую вызываете strxfrm(), он обрабатывает первый нулевой символ как терминатор. Не ожидайте, что преобразованные строки, которые он создаёт, будут портативными на разных системах — или даже между одной ревизией вашей операционной системы и следующей. Короче говоря, не вызывайте strxfrm() напрямую: позвольте Perl сделать это за вас.

Примечание: use locale не показан в некоторых из этих примеров, потому что он не нужен: strcoll() и strxfrm() — функции POSIX, которые используют стандартные системные функции libc, которые всегда следуют текущей локали LC_COLLATE.

Категория LC_CTYPE: Типы символов

В контексте формы use locale, включающей LC_CTYPE, Perl следует настройке локали LC_CTYPE. Это определяет представление приложения о том, какие символы являются алфавитными, цифровыми, пунктуационными и т. д. Это влияет на метанотацию \w регулярного выражения Perl, которая обозначает буквенно-цифровые символы — то есть алфавитные, цифровые и системный символ подчёркивания. (Обратитесь к perlre за дополнительной информацией о регулярных выражениях.) Благодаря LC_CTYPE, в зависимости от вашей настройки локали, символы, такие как «æ», «ð», «ß» и «ø», могут рассматриваться как \w символы. Это также влияет на такие вещи, как \s, \D, и классы символов POSIX, такие как [[:graph:]]. (См. perlrecharclass для получения дополнительной информации обо всём этом).

Локаль LC_CTYPE также предоставляет карту, используемую при транслитерации символов между верхним и нижним регистром. Это влияет на функции преобразования регистра —fc(), lc(), lcfirst(), uc(), и ucfirst(); интерполяцию преобразования регистра с \F, \l, \L, \u, или \U в строках с двойными кавычками и s/// замещениями; а также на сопоставление шаблонов регулярных выражений без учёта регистра с помощью модификатора i.

Начиная с версии v5.20, Perl поддерживает UTF-8 локали для LC_CTYPE, но в противном случае Perl поддерживает только локали с одним байтом, такие как серии ISO 8859. Это означает, что локали с широким набором символов, например, для азиатских языков, не поддерживаются должным образом. Использование таких локалей может привести к ошибке core dump. Если платформа предоставляет Perl возможность распознавать такую локаль, начиная с Perl v5.22, Perl будет предупреждать (по умолчанию включено) с помощью категории предупреждений locale, всякий раз, когда такая локаль переключается. Поддержка локали UTF-8 фактически является надмножеством локалей POSIX, поскольку она реализует полное поведение Unicode, как будто никакая локаль LC_CTYPE не используется вообще (за исключением загрязнения; см. "БЕЗОПАСНОСТЬ"). Локали POSIX, даже UTF-8, не обладают определёнными понятиями Unicode, такими как идея, что изменение регистра символа может расшириться до более чем одного символа. Perl в UTF-8 локали предоставит вам это расширение. До версии v5.20 Perl на некоторых платформах обрабатывал UTF-8 локаль как локаль ISO 8859-1 с некоторыми ограничениями, а на других платформах — как локаль "C". Для выпусков v5.16 и v5.18 use locale 'not_characters можно использовать в качестве обходного решения (см. "Unicode и UTF-8").

Обратите внимание, что некоторые вещи не зависят от текущей локали. Любой буквенный символ — это собственный символ для данной платформы. Таким образом, 'A' означает символ с кодовым значением 65 в ASCII-платформах и 193 в EBCDIC. Это может быть или не быть 'A' в текущей локали, если эта локаль вообще содержит 'A'. Аналогично, все escape-последовательности для конкретных символов, \n например, всегда означают собственный символ платформы. Это означает, что, например, \N в регулярных выражениях (любой символ, кроме новой строки) работает с набором символов платформы.

Начиная с версии v5.22, Perl по умолчанию будет выводить предупреждение при переключении в локаль, которая переопределяет любой печатный символ ASCII (плюс \t и \n) в класс, отличный от ожидаемого. Это, скорее всего, произойдёт на современных локалях только на EBCDIC-платформах, где, например, локаль CCSID 0037 на машине CCSID 1047 перемещает "[", но это может произойти и на ASCII-платформах с ISO 646 и другими 7-битовыми локалями, которые в основном устарели. Программа всё равно может работать, в зависимости от используемых функций Perl. Например, в примере выше, где "|" становится \w, и нет регулярных выражений, где это имеет значение, программа может работать правильно. Предупреждение перечисляет все символы, которые, по оценке, могут быть неблагоприятно затронуты.

Примечание: Некорректное или вредоносное определение локали LC_CTYPE может привести к тому, что явно неподходящие символы будут считаться буквенно-цифровыми вашим приложением. Для строгого сопоставления (обычных) ASCII-букв и цифр — например, в строках команд — приложения, учитывающие локаль, должны использовать \w с модификатором регулярного выражения /a. См. "БЕЗОПАСНОСТЬ".

Категория LC_NUMERIC: Форматирование чисел

После вызова POSIX::setlocale() и в рамках формы use locale которая включает числа, Perl подчиняется информации локали LC_NUMERIC, которая управляет представлением приложения о том, как числа должны форматироваться для удобочитаемости человеком. В большинстве реализаций единственным эффектом является изменение символа, используемого для десятичной точки — возможно, с "." на ",". Функции не осведомлены о таких тонкостях, как разделители тысяч и т. д. (См. "Функцию localeconv", если вас интересуют эти вещи.)

use POSIX qw(strtod setlocale LC_NUMERIC);
use locale;

setlocale LC_NUMERIC, "";

$n = 5/2;   # Assign numeric 2.5 to $n

$a = " $n"; # Locale-dependent conversion to string

print "half five is $n\n";       # Locale-dependent output

printf "half five is %g\n", $n;  # Locale-dependent output

print "DECIMAL POINT IS COMMA\n"
         if $n == (strtod("2,5"))[0]; # Locale-dependent conversion

См. также I18N::Langinfo и RADIXCHAR.

Категория LC_MONETARY: Форматирование денежных сумм

Стандарт C определяет категорию LC_MONETARY, но не функцию, которая зависит от её содержимого. (Те, кто имеет опыт работы с комитетами по стандартам, узнают, что рабочая группа решила не касаться этого вопроса.) Следовательно, Perl фактически не обращает на неё внимания. Если вы действительно хотите использовать LC_MONETARY, вы можете запросить её содержимое — см. "Функцию localeconv" — и использовать полученную информацию для собственного форматирования денежных сумм в вашем приложении. Однако, вы можете обнаружить, что информация, хоть и обширная и сложная, всё равно не вполне соответствует вашим требованиям: форматирование валюты — сложная задача.

См. также I18N::Langinfo и CRNCYSTR.

Категория LC_TIME: Представление времени

Вывод, произведённый функцией POSIX::strftime(), которая строит отформатированную строку даты/времени для удобочитаемости человеком, зависит от текущей локали LC_TIME. Таким образом, во французской локали вывод, произведённый элементом формата %B (полное название месяца) для первого месяца года, будет "janvier". Вот как получить список полных названий месяцев в текущей локали:

use POSIX qw(strftime);
for (0..11) {
    $long_month_name[$_] =
        strftime("%B", 0, 0, 0, 1, $_, 96);
}

Примечание: use locale в этом примере не требуется: strftime() — это функция POSIX, которая использует стандартную системную функцию libc, которая всегда подчиняется текущей локали LC_TIME.

См. также I18N::Langinfo и ABDAY_1..ABDAY_7, DAY_1..DAY_7, ABMON_1..ABMON_12, и ABMON_1..ABMON_12.

Другие категории

Остальные категории локалей в настоящее время не используются самим Perl. Но обратите внимание, что другие вещи, с которыми взаимодействует Perl, могут использовать их, включая расширения за пределами стандартного распределения Perl, а также операционную систему и её утилиты. Обратите особое внимание на то, что строковое значение $! и сообщения об ошибках, выдаваемые внешними утилитами, могут изменяться локалью LC_MESSAGES. Если вам нужны переносимые коды ошибок, используйте %!. См. Errno.

БЕЗОПАСНОСТЬ

Хотя основное обсуждение проблем безопасности Perl можно найти в perlsec, обсуждение обработки локалей Perl было бы неполным, если бы оно не обратило ваше внимание на проблемы безопасности, связанные с локалями. Локали — особенно на системах, которые позволяют пользователям без привилегий создавать свои собственные локали — ненадежны. Вредоносная (или просто некорректная) локаль может привести к неожиданным результатам в приложении, учитывающем локаль. Вот несколько возможных проблем:

  • Проверки регулярных выражений на безопасность имён файлов или адресов электронной почты с использованием \w могут быть обмануты локалью LC_CTYPE, которая утверждает, что символы, такие как ">" и "|", являются буквенно-цифровыми.

  • Интерполяция строк с преобразованием регистра, как, например, в $dest = "C:\U$name.$ext", может привести к опасным результатам, если в действительности существует ложный таблицы преобразования регистра LC_CTYPE.

  • Хитрая локаль LC_COLLATE может привести к тому, что имена студентов с оценкой "D" будут появляться перед теми, у кого оценка "A".

  • Приложение, которое заботится об использовании информации в LC_MONETARY, может форматировать дебиты как кредиты и наоборот, если эта локаль была взломана. Или оно может произвести платежи в долларах США вместо гонконгских долларов.

  • Даты и дни недели в датах, отформатированных функцией strftime(), могут быть изменены в угоду злоумышленнику, способному взломать локаль LC_DATE. ("Посмотрите — там написано, что я не был в здании в воскресенье.")

Такие опасности не специфичны для системы локалей: любая часть среды приложения, которая может быть изменена злонамеренно, представляет собой аналогичные проблемы. Аналогично, они не специфичны для Perl: любой язык программирования, который позволяет вам создавать программы, учитывающие их среду, подвергает вас этим проблемам.

Perl не может защитить вас от всех возможных проблем, показанных в примерах — здесь нет замены вашей собственной бдительности — но, когда use locale используется, Perl использует механизм защиты (см. perlsec), чтобы пометить строковые результаты, которые становятся зависимыми от локали и которые могут быть ненадежными в результате. Вот краткое описание поведения защиты операторов и функций, которые могут зависеть от локали:

  • Операторы сравнения (lt, le, ge, gt и cmp):

    Скалярный результат true/false (или меньше/равно/больше) никогда не заражается.

  • Интерполяция преобразования регистра (с \l, \L, \u, \U, или \F)

    Строка результата с интерполированным материалом заражается, если используется форма use locale , включающая LC_CTYPE.

  • Оператор сопоставления (m//):

    Скалярный результат true/false никогда не заражается.

    Все подмаски, либо переданные как результат контекста списка, либо как $1 и т.д., заражаются, если в действии форма use locale , включающая LC_CTYPE , а подмаска регулярного выражения содержит конструкцию, зависящую от локали. Эти конструкции включают \w (для сопоставления буквенно-цифрового символа), \W (небуквенно-цифрового символа), \b и \B (граница слова и не граница, которые зависят от того, что \w и \W совпадают), \s (пробельный символ), \S (непробельный символ), \d и \D (цифры и нецифры), а также POSIX-классы символов, такие как [:alpha:] (см. "POSIX Character Classes" в perlrecharclass).

    Заражение также вероятно, если шаблон должен быть сопоставлен без учета регистра (через /i). Исключением являются случаи, когда все кодовые точки, которые должны быть сопоставлены таким образом, находятся выше 255 и не имеют свёрток по правилам Юникода до значения ниже 256. Заражение для них не выполняется, так как Perl использует только правила Юникода для таких кодовых точек, а эти правила одинаковы независимо от текущей локали.

    Переменные сопоставленного шаблона, $&, $` (префикс), $' (постфикс) и $+ (последнее совпадение) также заражаются.

  • Оператор подстановки (s///):

    Обладает тем же поведением, что и оператор совпадения. Кроме того, левый операнд =~ становится заражённым, когда в действии форма use locale , включающая LC_CTYPE , если он изменяется в результате подстановки, основанной на сопоставлении с регулярным выражением, включающим любые из упомянутых в предыдущем пункте элементов, или преобразовании регистра, таких как \l, \L, \u, \U или \F.

  • Функции форматирования вывода (printf() и write()):

    Результаты никогда не заражаются, иначе даже вывод из print, например print(1/7), должен быть заражён, если use locale активен.

  • Функции преобразования регистра (lc(), lcfirst(), uc(), ucfirst()):

    Результаты заражаются, если в действии форма use locale , включающая LC_CTYPE.

  • Зависимые от локали функции POSIX (localeconv(), strcoll(), strftime(), strxfrm()):

    Результаты никогда не заражаются.

Три примера иллюстрируют заражение, зависящее от локали. Первая программа, которая игнорирует свою локаль, не будет запущена: значение, взятое непосредственно из командной строки, не может быть использовано для именования выходного файла при включенных проверках заражения.

#/usr/local/bin/perl -T
# Run with taint checking

# Command line sanity check omitted...
$tainted_output_file = shift;

open(F, ">$tainted_output_file")
    or warn "Open of $tainted_output_file failed: $!\n";

Программа может быть запущена путём «отбеливания» заражённого значения с помощью регулярного выражения: во втором примере — который по-прежнему игнорирует информацию о локали — программа запускается, создавая файл, названный в командной строке, если это возможно.

#/usr/local/bin/perl -T

$tainted_output_file = shift;
$tainted_output_file =~ m%[\w/]+%;
$untainted_output_file = $&;

open(F, ">$untainted_output_file")
    or warn "Open of $untainted_output_file failed: $!\n";

Сравните это с аналогичной, но учитывающей локаль программой:

#/usr/local/bin/perl -T

$tainted_output_file = shift;
use locale;
$tainted_output_file =~ m%[\w/]+%;
$localized_output_file = $&;

open(F, ">$localized_output_file")
    or warn "Open of $localized_output_file failed: $!\n";

Эта третья программа не запускается, потому что $& заражено: это результат сопоставления, включающего \w , в то время как use locale активен.

Окружение

PERL_SKIP_LOCALE_INIT

Эта переменная среды, доступная начиная с Perl v5.20, если она установлена (любым значением), сообщает Perl не использовать остальные переменные среды для инициализации. Вместо этого Perl использует текущие настройки локали. Это особенно полезно в встроенных средах, см. "Использование встроенного Perl с POSIX-локаль" в perlembed.

PERL_BADLANG

Строка, которая может подавить предупреждение Perl о сбое настроек локали при запуске. Сбой может произойти, если поддержка локали в операционной системе каким-то образом отсутствует (неисправна) — или если вы неправильно ввели имя локали при настройке окружения. Если эта переменная среды отсутствует или имеет значение, отличное от "0" или "", Perl сообщит о сбоях настройки локали.

ПРИМЕЧАНИЕ: PERL_BADLANG только предоставляет способ скрыть сообщение об ошибке. Сообщение сообщает о проблеме с поддержкой локали в вашей системе, и вы должны выяснить, в чём заключается проблема.

Следующие переменные окружения не являются специфичными для Perl: они являются частью стандартизированного (ISO C, XPG4, POSIX 1.c) setlocale() метода управления мнением приложения о данных. Windows не является POSIX, но Perl обеспечивает работу следующих способов описанным образом. Если локаль, заданная переменной окружения, недействительна, Perl пытается использовать следующую более низкую по приоритету. Если все значения недействительны, в Windows используется системная локаль по умолчанию. Если всё остальное не сработает, используется локаль "C". Если даже это не сработает, что-то серьёзно неисправно, но Perl пытается продолжить работу с теми настройками локали, которые могут быть.

LC_ALL

LC_ALL — переменная среды локали «переопределение всех». Если она установлена, она переопределяет все остальные переменные среды локали.

LANGUAGE

ПРИМЕЧАНИЕ: LANGUAGE — расширение GNU, оно влияет только при использовании GNU libc. Это происходит, если вы используете, например, Linux. Если вы используете «коммерческие» Unix-системы, вы, скорее всего, не используете GNU libc, и можете игнорировать LANGUAGE.

Однако, если вы используете LANGUAGE, это влияет на язык информационных, предупреждающих и сообщений об ошибках, выводимых командами (другими словами, это как LC_MESSAGES ), но имеет более высокий приоритет, чем LC_ALL. Более того, это не единственное значение, а «путь» (список разделённый двоеточием) языков (а не локалей). См. документацию библиотеки GNU gettext для получения дополнительной информации.

LC_CTYPE

При отсутствии LC_ALL, LC_CTYPE выбирает локаль типов символов. При отсутствии и LC_ALL и LC_CTYPE, LANG выбирает локаль типов символов.

LC_COLLATE

При отсутствии LC_ALL, LC_COLLATE выбирает локаль сортировки. При отсутствии и LC_ALL и LC_COLLATE, LANG выбирает локаль сортировки.

LC_MONETARY

При отсутствии LC_ALL, LC_MONETARY выбирает локаль денежного форматирования. При отсутствии и LC_ALL и LC_MONETARY, LANG выбирает локаль денежного форматирования.

LC_NUMERIC

При отсутствии LC_ALL, LC_NUMERIC выбирает локаль числового форматирования. При отсутствии и LC_ALL и LC_NUMERIC, LANG выбирает числовое форматирование.

LC_TIME

При отсутствии LC_ALL, LC_TIME выбирает локаль форматирования даты и времени. При отсутствии и LC_ALL и LC_TIME, LANG выбирает локаль форматирования даты и времени.

LANG

LANG — переменная среды локали «catch-all». Если она установлена, она используется в качестве последнего средства после общей LC_ALL и специфичных по категориям LC_foo.

Примеры

LC_NUMERIC управляет числовым выводом:

use locale;
use POSIX qw(locale_h); # Imports setlocale() and the LC_ constants.
setlocale(LC_NUMERIC, "fr_FR") or die "Pardon";
printf "%g\n", 1.23; # If the "fr_FR" succeeded, probably shows 1,23.

а также тем, как строки разбираются функцией POSIX::strtod() как числа:

use locale;
use POSIX qw(locale_h strtod);
setlocale(LC_NUMERIC, "de_DE") or die "Entschuldigung";
my $x = strtod("2,34") + 5;
print $x, "\n"; # Probably shows 7,34.

ПРИМЕЧАНИЯ

Строковая eval и LC_NUMERIC

Строка eval разбирает своё выражение как стандартный Perl. Поэтому она ожидает, что десятичная точка будет точкой. Если LC_NUMERIC установлена так, чтобы она была запятой вместо этого, разбор будет нарушен, возможно, без явного сообщения об ошибке.

use locale;
use POSIX qw(locale_h);
setlocale(LC_NUMERIC, "fr_FR") or die "Pardon";
my $a = 1.2;
print eval "$a + 1.5";
print "\n";

выводит 13,5. Это происходит потому, что в этой локали запятая — десятичная точка. eval таким образом расширяется до:

eval "1,2 + 1.5"

и результат не такой, как вы, вероятно, ожидали. Предупреждения не генерируются. Если вы выполняете строковый eval в области действия use locale, вам следует вместо этого изменить строку eval на что-то вроде:

print eval "no locale; $a + 1.5";

Это выводит 2.7.

Вы также можете исключить LC_NUMERIC, если вам это не нужно, путём

use locale ':!numeric';

Обратная совместимость

Версии Perl до 5.004 в основном игнорировали информацию о локали, обычно ведя себя так, как если бы что-то подобное локали "C" всегда было в силе, даже если окружение программы подсказывало обратное (см. "Функция setlocale"). По умолчанию Perl по-прежнему ведёт себя таким образом для обеспечения обратной совместимости. Если вы хотите, чтобы Perl-приложение обращало внимание на информацию о локали, вы должны использовать оператор use locale (см. "Оператор use locale") или, в маловероятном случае, если вы хотите сделать это только для сопоставления шаблонов, модификатор регулярного выражения /l (см. "Модификаторы наборов символов" в perlre) для его инструкции.

Версии Perl от 5.002 до 5.003 использовали информацию LC_CTYPE, если она была доступна; то есть \w понимал, какие буквы соответствуют переменным среды локали. Проблема заключалась в том, что пользователь не имел контроля над функцией: если C-библиотека поддерживала локали, Perl использовал их.

I18N: устаревшая сортировка

В версиях Perl до 5.004, сортировка с учетом локали была возможна с использованием модуля библиотеки I18N::Collate. Этот модуль теперь устарел и следует избегать в новых приложениях. Функциональность LC_COLLATE теперь интегрирована в ядро Perl: можно использовать локально-зависимые скалярные данные обычным образом с use locale, поэтому больше нет необходимости работать со скалярными ссылками I18N::Collate.

Скорость сортировки и использование памяти

Сравнение и сортировка с учетом локали обычно медленнее, чем по умолчанию; наблюдалось замедление в два-четыре раза. Это также потребует больше памяти: после того, как скалярная переменная Perl участвовала в любой операции сравнения строк или сортировки, подчиняющейся правилам сортировки с учетом локали, она будет занимать в 3-15 раз больше памяти, чем раньше. (Точный множитель зависит от содержимого строки, операционной системы и локали.) Эти недостатки обусловлены скорее реализацией системы локали операционной системой, чем Perl.

Свободно доступные определения локали

Проект Unicode CLDR извлекает часть POSIX многих своих локалей, доступных по адресу

https://unicode.org/Public/cldr/2.0.1/

(Более новые версии CLDR требуют самостоятельного вычисления данных POSIX. См. http://unicode.org/Public/cldr/latest/.)

Существует большая коллекция определений локали по адресу:

http://std.dkuug.dk/i18n/WG15-collection/locales/

Следует знать, что эта коллекция не поддерживается и не гарантируется пригодность для каких-либо целей. Если ваша система позволяет устанавливать произвольные локали, вы можете использовать эти определения как есть или как основу для разработки собственных локалей.

I18n и l10n

«Интэрнационализация» часто сокращается как i18n, поскольку ее первые и последние буквы разделены восемнадцатью другими. (Вы можете догадаться, почему сокращение internalin... internaliti... i18n так распространено.) Аналогично, «локализация» часто сокращается до l10n.

Несовершенный стандарт

Интернационализация, как определено в стандартах C и POSIX, может быть подвергнута критике как неполная и неуклюжая. Они также имеют тенденцию, как группы стандартов, делить мир на нации, когда всем известно, что мир можно также разделить на банкиров, байкеров, геймеров и так далее.

Unicode и UTF-8

Поддержка Unicode является новой, начиная с версии Perl v5.6, и более полно реализована в версиях v5.8 и более поздних. См. perluniintro.

Начиная с Perl v5.20, UTF-8 локали поддерживаются в Perl, за исключением LC_COLLATE, который поддерживается лишь частично; поддержка сортировки улучшена в Perl v5.26 до уровня, который может быть достаточным для ваших потребностей (см. "Категория LC_COLLATE: Сортировка: Сравнение и сортировка текста").

Если у вас Perl v5.16 или v5.18 и вы не можете обновить, вы можете использовать

use locale ':not_characters';

При использовании этой формы прагмы Perl использует только несимвольные части локалей, например LC_NUMERIC. Perl предполагает, что вы перевели все символы, с которыми он должен работать, в Unicode (фактически, в собственную кодировку платформы (ASCII или EBCDIC) плюс Unicode). Для данных в файлах это удобно сделать, также указав

use open ':locale';

Эта прагма обеспечивает перевод всех входных данных из файлов в Unicode из текущей локали, указанной в среде (см. "СРЕДА"), и перевод всех выходных данных в файлы обратно в локаль. (См. open). На уровне каждого файлового дескриптора можно вместо этого использовать модуль PerlIO::locale или модуль Encode::Locale, оба доступны из CPAN. Последний модуль также имеет методы для упрощения обработки ARGV и переменных среды, а также может использоваться для отдельных строк. Если вы знаете, что все ваши локали будут UTF-8, как многие из них сегодня, вы можете использовать параметр командной строки -C.

Эта форма прагмы позволяет по существу бесшовную обработку локалей с Unicode. Порядок сортировки будет по порядку кодовых точек Unicode. Unicode::Collate может использоваться для получения правил сортировки Unicode.

Все описанные модули и переключатели могут использоваться в v5.20 с обычной формой use locale, и если входные локали не UTF-8, вы получите неидеальное поведение, описанное ниже, которое вы получаете с Perl до версии v5.16, или когда вы используете прагму локали без параметра :not_characters в v5.16 и v5.18. Если вы используете исключительно UTF-8 локали в v5.20 и выше, остальная часть этого раздела к вам не относится.

Есть два случая: многобайтовые и однобайтовые локали. Сначала многобайтовые:

Единственная многобайтовая (или широкая) локаль, которую Perl, вероятно, будет поддерживать, — это UTF-8. Это связано с сложностью реализации, тем фактом, что качественные локали UTF-8 теперь опубликованы для каждой области мира (https://unicode.org/Public/cldr/2.0.1/ для уже настроенных, но из более ранней версии; https://unicode.org/Public/cldr/latest/ для самых актуальных, но вам нужно самостоятельно извлечь информацию POSIX), и что в любом случае вы можете использовать модуль Encode для перевода в/из вашей локали. Поэтому вам нужно сделать что-то из этого, если вы используете такие локали, как Big5 или Shift JIS. Для UTF-8 локалей в Perl (до версии v5.20), которые не имеют полной поддержки UTF-8 локалей, они могут работать достаточно хорошо (в зависимости от реализации вашей C-библиотеки), просто потому, что как они, так и Perl хранят символы, занимающие несколько байтов, одинаковым образом. Однако некоторые, если не большинство, реализации C-библиотек могут не обрабатывать символы в верхней половине диапазона Latin-1 (128 - 255) должным образом в LC_CTYPE. Чтобы узнать, является ли символ определенного типа в локали, Perl использует функции, такие как isalnum(). Ваша C-библиотека может не работать для UTF-8 локалей с этими функциями, вместо этого работая только в новых функциях широких библиотек, таких как iswalnum(), которые Perl не использует. Эти многобайтовые локали обрабатываются как однобайтовые, и будут иметь ограничения, описанные ниже. Начиная с Perl v5.22, отображается сообщение об ошибке, когда Perl обнаруживает многобайтовую локаль, которую он не полностью поддерживает.

Для однобайтовых локалей Perl, как правило, использует правила локали для кодовых точек, которые могут поместиться в один байт, и правила Unicode для тех, которые не могут (хотя это не применяется повсеместно, см. примечание в конце этого раздела). Это предотвращает многие проблемы в локалях, которые не являются UTF-8. Предположим, что локаль — ISO8859-7, греческий. Символ в 0xD7 там — заглавная буква Хи. Но в локали ISO8859-1, Latin1, это знак умножения. Класс символов POSIX [[:alpha:]] волшебным образом будет соответствовать 0xD7 в греческой локали, но не в латинской.

Однако есть места, где это ломается. Некоторые конструкции Perl предназначены только для Unicode, например \p{Alpha}. Они предполагают, что 0xD7 всегда имеет свое значение Unicode (или эквивалент на платформах EBCDIC). Поскольку Latin1 — подмножество Unicode, а 0xD7 — знак умножения как в Latin1, так и в Unicode, \p{Alpha} никогда не будет соответствовать ему, независимо от локали. Аналогичная проблема возникает с \N{...}. До v5.20, поэтому не рекомендуется использовать \p{} или \N{} в простой use locale—если вы можете гарантировать, что локаль будет ISO8859-1. Используйте вместо этого классы символов POSIX.

Другая проблема с этим подходом заключается в том, что операции, пересекающие границу один байт/несколько байтов, не определены и поэтому запрещены. (Эта граница находится между кодовыми точками 255/256.) Например, преобразование в нижний регистр LATIN CAPITAL LETTER Y WITH DIAERESIS (U+0178) должно вернуть LATIN SMALL LETTER Y WITH DIAERESIS (U+00FF). Но в греческой локали, например, нет символа в 0xFF, и Perl не знает, что же на самом деле должно представлять собой символ в 0xFF. Поэтому он запрещает эту операцию. В этом режиме строчная буква U+0178 — это сама себя.

Те же проблемы возникают, если вы включите автоматическое преобразование в UTF-8 ваших стандартных файловых дескрипторов, стандартный open() уровень и @ARGV в локалях, отличных от ISO8859-1 и UTF-8 (используя либо параметр командной строки -C, либо переменную среды PERL_UNICODE ; см. perlrun). Вещи читаются как UTF-8, что обычно предполагает интерпретацию Unicode, но наличие локали заставляет их интерпретироваться в этой локали вместо этого. Например, кодовая точка 0xD7 в входных данных Unicode, которая должна означать знак умножения, не будет интерпретироваться Perl так в греческой локали. Это не проблема, если вы позаботитесь о том, чтобы все локали всегда и только были либо ISO8859-1, либо, если у вас нет недостатков в C-библиотеке, UTF-8.

Еще одна проблема в том, что этот подход может привести к тому, что две кодовые точки будут обозначать один и тот же символ. Например, в греческой локали и U+03A7, и U+00D7 — это GREEK CAPITAL LETTER CHI.

Из-за всех этих проблем, начиная с версии v5.22, Perl будет выводить предупреждение, если многобайтовая (следовательно, Unicode) кодовая точка используется, когда активна однобайтовая локаль. (Хотя он не проверяет это, если это приведет к необоснованному замедлению выполнения.)

Локали поставщиков печально известны своими ошибками, и Perl сложно протестировать свой код обработки локалей, потому что это взаимодействует с кодом, которым Perl не управляет; поэтому код обработки локалей в Perl также может быть ошибочным. (Однако локали, предоставленные Unicode, должны быть лучше, и есть механизм обратной связи для исправления любых проблем. См. "Свободно доступные определения локали".)

Если у вас Perl v5.16, проблемы, упомянутые выше, исчезают, если вы используете параметр :not_characters для прагмы локали (за исключением ошибок поставщиков в несимвольных частях). Если у вас нет v5.16, а у вас есть локали, которые работают, использование их может быть целесообразным для определенных конкретных целей, если вы помните о проблемах, упомянутых ранее. Например, если сортировка для ваших локалей работает, она выполняется быстрее в локалях, чем в Unicode::Collate; и вы получаете доступ к таким вещам, как символ местной валюты и названия месяцев и дней недели. (Но, чтобы подчеркнуть, в v5.16 вы получаете этот доступ без недостатков локалей, используя форму прагмы :not_characters.)

Примечание: Политика использования правил локали для кодовых точек, которые могут поместиться в один байт, и правил Unicode для тех, которые не могут, не применяется повсеместно. До версии 5.12 она была несколько случайной; в версии 5.12 она применялась довольно последовательно к сопоставлению с регулярными выражениями, за исключением заключенных в квадратные скобки классов символов; в версии 5.14 она была расширена на все соответствия с регулярными выражениями; а в версии 5.16 — на операции преобразования регистра, такие как \L и uc(). Для сортировки в всех выпусках до сих пор вызывается функция системы strxfrm(), и то, что она делает, — это то, что вы получаете. Начиная с версии 5.26, исправлены различные ошибки в способе использования Perl этой функции.

ОШИБКИ

Сортировка строк, содержащих встроенные символы NUL

Символы NUL будут сортироваться так же, как и самый низкий управляющий символ сортировки, или до "\001" в маловероятном случае, если в локали вообще нет управляющих символов. В тех случаях, когда строки не содержат этот не-NUL управляющий символ, результаты будут правильными, и во многих локалях этот управляющий символ, каким бы он ни был, встречается редко. Но есть случаи, когда NUL должен сортироваться раньше этого управляющего символа, но этого не происходит. Если две строки сортируются идентично, строка, содержащая NUL будет сортироваться раньше. До версии 5.26 было больше ошибок.

Многопоточность

Код XS или библиотеки на языке C, вызываемые из него, которые используют системную функцию setlocale(3) (за исключением Windows), вероятно, не будут работать из многопоточного приложения без изменений. См. "Локализованный код XS в perlxs".

Модуль XS, зависящий от локали, мог быть написан с предположением, что он никогда не будет вызван в многопоточной среде, и поэтому использует другие нелокализованные конструкции, которые не являются безопасными для многопоточности. См. "Многопоточные системные интерфейсы в perlxs".

POSIX не определяет способ получения имени текущей локали каждого потока. Некоторые системы, такие как Darwin и NetBSD, реализуют функцию querylocale(3) для этого. На системах, не являющихся Windows, без неё, таких как Linux, есть некоторые дополнительные оговорки:

  • Встроенный perl должен быть запущен, пока глобальная локаль активна. См. "Использование встроенного Perl с POSIX-локальностью в perlembed".

  • Для perl становится важнее знать обо всех возможных категориях локали на платформе, даже если они, по-видимому, не используются в вашей программе. Perl знает все категории Linux. Если ваша платформа имеет другие, вы можете создать вопрос на https://github.com/Perl/perl5/issues для включения её в следующий релиз. Тем временем можно отредактировать исходный код Perl, чтобы он узнавал о категории, и затем перекомпилировать. Поищите в исходном коде примеры, например, LC_PAPER, и используйте их в качестве шаблона для добавления пропущенной.

  • Возможны, хотя и трудно реализуемые, вызовы POSIX::setlocale с локалью, которую он не распознаёт как синтаксически корректную, но которая на самом деле является корректной на этой системе. Это должно происходить только с встроенными perl или если вы создаёте имя локали самостоятельно.

Неисправные системы

На некоторых системах поддержка локали операционной системы неисправна и не может быть исправлена или использована Perl. Такие недостатки могут и будут приводить к загадочным зависаниям и/или дампам ядра Perl, когда use locale активна. При столкновении с такой системой, пожалуйста, подробно сообщите об этом на <https://github.com/Perl/perl5/issues>, а также обратитесь к своему поставщику: исправления ошибок для этих проблем могут существовать в вашей операционной системе. Иногда такие исправления ошибок называются обновлением операционной системы. Если у вас есть исходный код Perl, включите в отчёт об ошибке вывод теста, описанного выше в "Тестирование на неисправные локали".

См. также

I18N::Langinfo, perluniintro, perlunicode, open, "localeconv" в POSIX, "setlocale" в POSIX, "strcoll" в POSIX, "strftime" в POSIX, "strtod" в POSIX, "strxfrm" в POSIX.

Дополнительные соображения при встроенном Perl в программе C см. в "Использование встроенного Perl с POSIX-локальностью в perlembed".

ИСТОРИЯ

Оригинальный perli18n.pod Джарко Хиетаниеми сильно модифицирован Домиником Данлопом, при содействии perl5-разработчиков. Проза немного переработана Томом Кристиансеном и теперь поддерживается разработчиками Perl 5.

© 1993–2021 Larry Wall and others
Licensed under the GNU General Public License version 1 or later, or the Artistic License.
The Perl logo is a trademark of the Perl Foundation.
https://perldoc.perl.org/5.34.0/perllocale

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API