Підтримка Unicode

Починаючи з Perl версії 5.6, в інтерпретаторі була реалізована підтримка Unicode на рівні мови. У цьому тексті йтиметься про те, навіщо це потрібно, як це можна використовувати, і з якими проблемами вам доведеться зіткнутися.

Зміст

Кожен UTF формат звернемо, тобто підтримує перетворення з послідовності Unicode-символів і назад без втрат, тобто: в результаті перетворення будь-якої послідовності Unicode-символівS на послідовність байтів і назад ми отримаємо зновуS. Для досягнення можливості перетворення без втрат в обидві сторони, формат UTF повинен визначати перетворення для всіх символів Unicode, навіть невалідних.

Вільний скорочений переклад What is a UTF?

Perl та Unicode

Unicode у Perl 5.6.x та 5.8.x

Підтримка Unicode в Perl 5.6 прив'язана до операцій, а не даних, що вимагає використання прагми "utf8" і тільки тоді, коли програміст впевнений, що всі дані в кодуванні UTF-8. Також Perl 5.6 не підтримує Unicode у регулярних виразах, що дуже сильно обмежує коло можливостей.

Я знаю надто мало про застосування Unicode у 5.6, так що і писати про це не можу. Всі приклади та текст нижче стосуються Perl 5.8.x. Якщо хтось хоче, то може висвітлити особливості 5.6. Закіров Руслан [досьє]

Як реалізовано підтримку в Perl

Будь-яка структура даних (скаляр, масив, хеш. ) Perl має набір прапорів, які відбивають ті чи інші властивості об'єктів. Для реалізації повноцінної підтримки Unicode було обрано формат UTF-8 та введено однойменний прапор. Всі функції, які так чи інакше працюють із рядками, враховують прапор та інтерпретують дані по-різному залежно від його значення. До таких функцій відносяться: length, chr, ord, substr, join, регулярні виразита інші. Наступний приклад демонструє відмінності в поведінці (модуль Encode, що використовується, включений в дистрибутив Perl починаючи з Perl 5.8):

Одна і та ж інформація у двох форматах: послідовність байтів (октетів) у кодуванні CP1251 з вимкненим прапором та послідовність символів у кодуванні UTF-8 із встановленим прапором. Функція length в обох випадках повертає те саме значення, тому що в cp1251 для зберігання одного символу використовується один байт, а для рядків без прапора повертається саме кількість байт. Відмінності у поведінці функцій ord і substr видно очевидно. Для експерименту спробуйте вимкнути прапор UTF-8, для цього розкоментуйте рядок Encode::_utf8_off($string); .

Які кодування підтримуються в Perl

Як вже було сказано вище, Perl перетворює зі "старих" кодувань в UTF-8, для всіх перетворень використовується модуль Encode, тобто від цього модуля залежить ви зможете використовувати переваги автоматичного перетворення даних.

Для кожного кодування, яке підтримується, безумовно "канонічне" ім'я і можливий ряд синонімів. Також назви кодувань не чутливі до регістру літер, а прогалини замінюються дефіс.

Різні кодування згруповані в модулі, наприклад підтримка кодувань UTF-* реалізована в модулі Encode::Unicode. Немає необхідності підвантажувати ці модулі самостійно, але можливо для кодувань, що рідко використовуються, доведеться встановити додаткові модулі з CPAN .

Переглянути всі канонічні імена всіх кодувань можна за допомогою

або подивитися канонічні імена підтримувані окремим модулем

Якщо ви не можете знайти в списку необхідне кодування, можливо це синонім будь-якого іншого кодування. Можна використовувати наступний невеликий скрипт длявизначення підтримується чи те чи інше кодування, і є назва канонічним або це синонім:

Докладно про те, які кодування підтримуються, дивіться perldoc Encode::Supported .

Perl та стандарти

Існує стандарт описує UTF-8. Стандарт досить суворий щодо того, що вважається UTF-8, а що ні. Наприклад, UTF-8 - це послідовність чисел в діапазоні від 0 до 0x10FFFF, але і в цьому діапазоні є заборонені значення.

Коли не можна використовувати Unicode

Не можна використовувати Unicode у таких ситуаціях (актуально для 5.8.x):

  1. назви пакетів/класів
  2. назви функцій

Модулі, прагми, змінні та опції

Прагма дозволяє вказати, що код програми написано у кодуванні UTF-8. Рядкові константи, константні шаблони в регулярних виразах та імена змінних будуть розглядатися як рядки в кодуванні UTF-8.

Прагма utf8 не впливає на роботу потоків введення/виводу (див. encoding та open). Прагма також не впливає на інтерпретацію рядків зі скинутим прапором UTF-8 (див. Конкатенація рядків з прапором і без прапора).

use encoding;

Багатофункціональна прагма. Дозволяє явно вказати кодування в якому написано ваш скрипт, наприклад CP1251 або будь-яке інше, яке підтримує модуль Encode. Також можна керувати поведінкою стандартних потоків введення/виводу (STD). І останнє, у випадках, коли інтерпретатору perl необхідно перетворити рядок без UTF-8 прапора на рядок з прапором, то зазначене кодування буде використане для перетворення. Розглянемо кожен із трьох пунктів окремо.

  1. Автоматична конвертація констант із кодування вказаного в UTF-8 з виставленням прапора. Дія в даному випадку дуже схожана дію прагми utf8, крім того, що кодування можна вказати явно.
  2. Управління стандартними потоками вводу/виводу. Ви можете вказати, в якому кодуванні інтерпретатор повинен виводити в стандартний потік виведення та/або з якого кодування перетворювати дані зі стандартного потоку введення. Тобто perl оперує Unicode даними, а під час виведення чи введення зі стандартних потоків здійснює автоматичну конвертацію даних.
  3. Останній пункт більш детально розглянутий в описі нижче. Коротко це єдина можливість вказати perl'у як інтерпретувати рядки без прапора, коли інтерпретатору необхідно конвертувати рядок в UTF-8 (за замовчуванням використовується latin-1).

Вивели коди літер та отримали UTF-8 (перші чотири рядки). В останньому рядку отримали слово 'тест' у кодуванні 'koi8-r', виведене на 'cp1251' термінал.

use open; (Прагма)

Прагма open - це додатковий інтерфейс для визначення "урівнів" за умовчанням для всіх потоків введення/виводу. Замість терміна "рівень (layer)" також використовується термін "дисципліна (discipline)". У будь-яких двоаргументних викликах open() , readpipe() (він же qx// ) і в подібних операторах, що знаходяться в межах лексичної області видимості цієї прагми, будуть використані зазначені значення за замовчуванням. Три-аргументні викликине піддаються дії цієї прагми і ви повинні вказувати рівні самостійно.

За допомогою підпрагми IN можна вказати, з якого кодування перетворювати дані зі стандартного потоку введення.

За допомогою підпрагми OUT можна вказати, в якому кодуванні інтерпретатор повинен виводити дані у стандартний потік виведення.

Якщо ви хочете задати кодування явно, використовуйте :encoding(. )

Якщо ви хочете, щоб кодування буливибрані автоматично відповідно до встановленої в системі локалі, то використовуйте :locale, приклад:

Це аналогічно до цього

Якщо у виклику open() вказано явний список рівнів, він додається до списку, який оголошено за допомогою прагми open.

Підпрагма :std сама по собі ні на що не впливає, але в поєднанні з підпрагмою :utf8 або :encoding вона призначає вибране кодування для стандартних файлових маніпуляторів (STDIN, STDOUT, STDERR). Наприклад, якщо оголосити прагму :utf8 для потоків введення та виведення, то :std також встановить :utf8 для файлових маніпуляторів STDIN, STDOUT, STDERR. В іншому випадку, якщо оголосити прагму :encoding(koi8r) для потоку виведення, то :std встановить koi8r тільки для файлових маніпуляторів STDOUT та STDERR. Підпрагма :locale неявно включає підпрагму :std

Логіка підпрагми :locale

Якщо платформа підтримує інтерфейс langinfo(CODESET), то значення, що ним повертається, використовується як базове кодування прагми open. Якщо платформа підкачала, але оголошена прагма locale, то для встановлення базового кодування прагми open використовується частина (після .) значення змінних оточення LC_ALL і LANG (у цьому порядку) придатна для назви кодування (якщо вона знайдена). Якщо перші два пункти безуспішні, але в значеннях змінних оточення LC_ALL і LANG (у цьому за порядком) знайдено щось схоже на UTF-8, то базовим кодуванням прагми open встановлюється :utf8. Якщо в значеннях змінних оточення (LC_ALL, LC_CTYPE, LANG) знайдено рядок 'UTF-8' або 'UTF8' (не важливо у якому регістрі), то базовим кодуванням для стандартних файлових маніпуляторів STDIN, STDOUT і STDERR, а також будь-яких файлових маніпуляторів відкритих пізніше встановлюється :utf8

Керування поведінкою за замовчуванням під час запускуінтерпретатора

Починаючи з версії 5.8.1, була додана опція інтерпретатора -C , яка дозволяє задати режими роботи з потоками вводу/виводу та масивом @ARGV за замовчуванням.