Почему современный Perl избегает UTF-8 по умолчанию?

Интересно, почему большинство современных решений, построенных с использованием Perl, по умолчанию не поддерживают UTF-8.

Я понимаю, что для основных скриптов Perl существует много проблем, которые могут сломать вещи. Но, с моей точки зрения, в 21 - м веке, большие новые проекты (или проекты с большой перспективой) должны сделать их программное обеспечение UTF-8 доказательство с нуля. Тем не менее я не вижу, что это происходит. Например, Moose разрешает строгие и предупреждения, но не Unicode. Modern :: Perl тоже уменьшает шаблон, но не обрабатывает UTF-8.

Зачем? Есть ли причины избегать использования UTF-8 в современных проектах Perl в 2011 году?


Комментировать @tchrist слишком долго, поэтому я добавляю его сюда.

Кажется, я не прояснил себя. Позвольте мне попытаться добавить некоторые вещи.

Мы с Тристом видим ситуацию примерно одинаково, но наши выводы полностью противоположны. Я согласен, ситуация с Unicode сложная, но именно поэтому нам (пользователям и программистам Perl) нужен какой-то слой (или прагма), который делает обработку UTF-8 настолько простой, насколько это должно быть в наши дни.

Чрист указал на многие аспекты, которые я хочу охватить, я буду читать и думать о них в течение нескольких дней или даже недель. Тем не менее, это не моя точка зрения. Чрист пытается доказать, что не существует единственного способа "включить UTF-8". У меня не так много знаний, чтобы спорить с этим. Итак, я придерживаюсь живых примеров.

Я играл с Rakudo, и UTF-8 был там, где мне было нужно. У меня не было никаких проблем, это просто сработало. Может быть, есть некоторые ограничения где-то глубже, но в начале все, что я тестировал, работало так, как я ожидал.

Разве это не должно быть целью и в современном Perl 5? Я подчеркиваю это больше: я не предлагаю UTF-8, как набор символов по умолчанию для ядра Perl, я предлагаю возможность вызвать его с помощью оснастки для тех, кто разрабатывает новые проекты.

Еще один пример, но с более негативным тоном. Фреймворки должны облегчить разработку. Несколько лет назад я попробовал веб-фреймворки, но просто выбросил их, потому что "включение UTF-8" было настолько неясным. Я не нашел, как и где подключить поддержку Unicode. Это было так много времени, что мне было легче идти по старому пути. Теперь я увидел, что здесь есть щедрость для решения той же проблемы с Mason 2: Как сделать Mason2 UTF-8 чистым? , Итак, это довольно новый фреймворк, но для его использования с UTF-8 требуется глубокое знание его внутренних возможностей. Это как большой красный знак: СТОП, не используйте меня!

Мне очень нравится Perl. Но иметь дело с Юникодом больно. Я все еще бегаю по стенам. В некотором смысле tchrist прав и отвечает на мои вопросы: новые проекты не привлекают UTF-8, потому что это слишком сложно в Perl 5.

Ответ 1

℞ ℞: 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨

  1. Установите для вашего PERL_UNICODE envariable значение AS. Это заставляет все сценарии Perl декодировать @ARGV как строки UTF ‑ 8 и устанавливает кодировку всех трех параметров stdin, stdout и stderr в UTF ‑ 8. И то, и другое - глобальные, а не лексические эффекты.

  2. В верхней части исходного файла (программа, модуль, библиотека, хиккей do), явно утверждайте, что вы используете Perl версии 5.12 или выше через:

    use v5.12;  # minimal for unicode string feature
    use v5.14;  # optimal for unicode string feature
    
  3. Включите предупреждения, поскольку предыдущее объявление включает только ограничения и функции, а не предупреждения. Я также предлагаю превратить предупреждения Unicode в исключения, поэтому используйте обе эти строки, а не одну из них. Тем не менее, обратите внимание, что в v5.14 класс предупреждений utf8 содержит три других подзапуска, которые могут быть включены по отдельности: nonchar, surrogate и non_unicode. Этими вы, возможно, захотите иметь больший контроль над.

    use warnings;
    use warnings qw( FATAL utf8 );
    
  4. Объявите, что этот источник кодируется как UTF ‑ 8. Хотя когда-то давно эта прагма делала другие вещи, теперь она служит одной единственной цели, а не другим:

    use utf8;
    
  5. Объявите, что все, что открывает файловый дескриптор в этой лексической области, но не где-либо еще, означает, что этот поток закодирован в UTF-8, если вы не укажете иначе. Таким образом, вы не затрагиваете другие модули или код других программ.

    use open qw( :encoding(UTF-8) :std );
    
  6. Включить именованные символы с помощью \N{CHARNAME}.

    use charnames qw( :full :short );
    
  7. Если у вас есть дескриптор DATA, вы должны явно установить его кодировку. Если вы хотите, чтобы это был UTF-8, то скажите:

    binmode(DATA, ":encoding(UTF-8)");
    

Конечно, нет конца другим вопросам, которые могут в конечном итоге вас заинтересовать, но их будет достаточно, чтобы приблизиться к государственной цели "заставить все просто работать с UTF-8", хотя и для несколько ослабленного смысла этих терминов.

Еще одна прагма, хотя она не связана с Unicode, это:

      use autodie;

Настоятельно рекомендуется.

D 🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 D


        D 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 🐪 D


Мой собственный шаблон в наши дни выглядит следующим образом:

use 5.014;

use utf8;
use strict;
use autodie;
use warnings; 
use warnings    qw< FATAL  utf8     >;
use open        qw< :std  :utf8     >;
use charnames   qw< :full >;
use feature     qw< unicode_strings >;

use File::Basename      qw< basename >;
use Carp                qw< carp croak confess cluck >;
use Encode              qw< encode decode >;
use Unicode::Normalize  qw< NFD NFC >;

END { close STDOUT }

if (grep /\P{ASCII}/ => @ARGV) { 
   @ARGV = map { decode("UTF-8", $_) } @ARGV;
}

$0 = basename($0);  # shorter messages
$| = 1;

binmode(DATA, ":utf8");

# give a full stack dump on any untrapped exceptions
local $SIG{__DIE__} = sub {
    confess "Uncaught exception: @_" unless $^S;
};

# now promote run-time warnings into stack-dumped
#   exceptions *unless* we're in an try block, in
#   which case just cluck the stack dump instead
local $SIG{__WARN__} = sub {
    if ($^S) { cluck   "Trapped warning: @_" } 
    else     { confess "Deadly warning: @_"  }
};

while (<>)  {
    chomp;
    $_ = NFD($_);
    ...
} continue {
    say NFC($_);
}

__END__

                   D 𝕹 𝕸 𝖆 𝖌 𝖈 𝖈 𝖚 𝖑 𝖑 D D


Сказать, что "Perl должен каким-то образом [!] включить Unicode по умолчанию" даже не начинает задумываться о том, чтобы сказать достаточно, чтобы быть даже незначительно полезным в каком-то редком и изолированном случае. Юникод - это намного больше, чем просто большой репертуар персонажей; Кроме того, все эти персонажи взаимодействуют по-разному.

Даже простейшие минимальные меры, которые (некоторые) люди думают, что они хотят, гарантированно сокрушат миллионы строк кода, кода, который не имеет шансов "обновить" до вашего изящного нового модного мира Brave New World.

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

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


         D 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 D


Как минимум, вот некоторые вещи, которые могут потребоваться, чтобы '"включил Юникод по умолчанию", как вы выразились:

  1. Все 🐪 исходный код должен быть в UTF-8 по умолчанию. Вы можете получить это с помощью use utf8 или export PERL5OPTS=-Mutf8.

  2. Ручка 🐪 DATA должна быть UTF-8. Вам придется делать это отдельно для каждого пакета, как в binmode(DATA, ":encoding(UTF-8)").

  3. Программные аргументы скриптов by следует понимать как UTF-8 по умолчанию. export PERL_UNICODE=A, или perl -CA, или export PERL5OPTS=-CA.

  4. Стандартные потоки ввода, вывода и ошибок должны по умолчанию использовать UTF-8. export PERL_UNICODE=S для всех из них или I, O и/или E только для некоторых из них. Это похоже на perl -CS.

  5. Любые другие дескрипторы, открытые 🐪, должны рассматриваться как UTF-8, если не указано иное; export PERL_UNICODE=D или с i и o для конкретных из них; export PERL5OPTS=-CD будет работать. Это делает -CSAD для всех из них.

  6. Покройте обе базы плюс все потоки, которые вы открываете с помощью export PERL5OPTS=-Mopen=:utf8,:std. См. уникальная цитата.

  7. Вы не хотите пропустить ошибки кодирования UTF-8. Попробуйте export PERL5OPTS=-Mwarnings=FATAL,utf8. И убедитесь, что ваши входные потоки всегда от binmode d до :encoding(UTF-8), а не только до :utf8.

  8. Кодовые точки между 128–255 следует понимать как the как соответствующие кодовые точки Unicode, а не просто незаполненные двоичные значения. use feature "unicode_strings" или export PERL5OPTS=-Mfeature=unicode_strings. Это сделают uc("\xDF") eq "SS" и "\xE9" =~ /\w/. Простой export PERL5OPTS=-Mv5.12 или лучше также получит это.

  9. Именованные символы Юникода по умолчанию не включены, поэтому добавьте export PERL5OPTS=-Mcharnames=:full,:short,latin,greek или что-то подобное. См. uninames и tcgrep.

  10. Вам почти всегда нужен доступ к функциям из стандартного Unicode::Normalize модуля различных типов разложений. export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD, а затем всегда запускать входящий материал через NFD и исходящий материал из NFC. Для них еще нет уровня ввода/вывода, о котором я знаю, но см. nfc, nfd, nfkd и nfkc.

  11. Сравнение строк в 🐪 с использованием eq, ne, lc, cmp, sort и & c & cc всегда неверно. Поэтому вместо @a = sort @b вам нужен @a = Unicode::Collate->new->sort(@b). Можно также добавить это к вашему export PERL5OPTS=-MUnicode::Collate. Вы можете кэшировать ключ для бинарных сравнений.

  12. 🐪 встроенные модули, такие как printf и write, неправильно работают с данными Unicode. Вам необходимо использовать модуль Unicode::GCString для первого, и оба, а также модуль Unicode::LineBreak для второго. См. uwc и unifmt.

  13. Если вы хотите, чтобы они считались целыми числами, то вам нужно будет выполнить ваши захваты \d+ через функцией Unicode::UCD::num, потому что встроенный atoi (3) в настоящее время недостаточно умен.

  14. У вас будут проблемы с файловой системой на 👽 файловых системах. Некоторые файловые системы молча принудительно преобразуют в NFC; другие молча предписывают переход в NFD. А другие еще что-то делают. Некоторые даже полностью игнорируют этот вопрос, что приводит к еще большим проблемам. Таким образом, вы должны выполнить свою собственную обработку NFC/NFD, чтобы сохранить здравый смысл.

  15. Весь ваш код, включающий a-z или A-Z и тому подобное , ДОЛЖЕН БЫТЬ ИЗМЕНЕН, включая m//, s/// и tr///. Он должен выделяться как кричащий красный флаг о том, что ваш код не работает. Но не ясно, как это должно измениться. Получить правильные свойства и понять их падеж сложнее, чем вы думаете. Я использую unichars и uniprops каждый день.

  16. Код, использующий \p{Lu}, почти так же неверен, как и код, использующий [A-Za-z]. Вам нужно использовать \p{Upper} вместо этого и знать причину. Да, \p{Lowercase} и \p{Lower} отличаются от \p{Ll} и \p{Lowercase_Letter}.

  17. Код, который использует [a-zA-Z], еще хуже. И он не может использовать \pL или \p{Letter}; он должен использовать \p{Alphabetic}. Знаете, не все алфавиты - это буквы!

  18. Если вы ищете 🐪 переменных с /[\$\@\%]\w+/, то у вас есть проблема. Вам нужно искать /[\$\@\%]\p{IDS}\p{IDC}*/, и даже он не думает о переменных пунктуации или переменных пакета.

  19. Если вы проверяете наличие пробелов, вам следует выбрать между \h и \v, в зависимости. И вы никогда не должны использовать \s, поскольку он НЕ ЗНАЧИТ [\h\v], вопреки распространенному мнению.

  20. Если вы используете \n для границы линии или даже \r\n, то вы делаете это неправильно. Вы должны использовать \R, что не то же самое!

  21. Если вы не знаете, когда и нужно ли вызывать Unicode :: Stringprep, тогда вам лучше учиться.

  22. Сравнение без учета регистра должно проверять, являются ли две вещи одинаковыми буквами, независимо от их диакритики и тому подобного. Самый простой способ сделать это с помощью стандартного модуля Unicode :: Collate. Unicode::Collate->new(level => 1)->cmp($a, $b). Существуют также методы eq и тому подобное, и вы, вероятно, также должны узнать о методах match и substr. Они имеют явные преимущества по сравнению со встроенными модулями.

  23. Иногда этого все еще недостаточно, и вместо этого вам нужен модуль Unicode :: Collate :: Locale, как в Unicode::Collate::Locale->new(locale => "de__phonebook", level => 1)->cmp($a, $b). Предположим, что Unicode::Collate::->new(level => 1)->eq("d", "ð") истинно, а Unicode::Collate::Locale->new(locale=>"is",level => 1)->eq("d", " ð") ложно. Точно так же "ae" и "æ" - это eq, если вы не используете локали или английский, но они отличаются в исландской локали. Что теперь? Это трудно, я говорю вам. Вы можете поиграть с ucsort, чтобы проверить некоторые из этих вещей.

  24. Рассмотрим, как сопоставить шаблон CVCV (согласный, гласный, согласный, гласный) в строке 'niño'. Его форма NFD - которую вы чертовски хорошо запомнили, чтобы вставить ее - становится "nin\x {303} o". Теперь, что ты собираешься делать? Даже притворяясь, что гласный - это [aeiou] (что, кстати, неправильно), вы также не сможете сделать что-то вроде (?=[aeiou])\X), потому что даже в NFD кодовая точка, подобная 'ø , не разлагается! Тем не менее, он будет тестироваться равным не используя сравнение UCA, которое я только что показал вам. Вы не можете полагаться на НФД, вы должны полагаться на УЦА.


              D 𝔸 𝕤 𝕤 𝕦 𝕞 𝔹 𝔹 D 𝕖 𝕖 D D D


И это еще не все. Есть миллион ошибочных предположений о Unicode. Пока они не поймут эти вещи, их код 🐪 будет нарушен.

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

  2. Код, который предполагает кодировку по умолчанию, является неким родным кодированием платформы.

  3. Код, который предполагает, что веб-страницы на японском или китайском языках занимают меньше места в UTF ‑ 16, чем в UTF ‑ 8, неверен.

  4. Код, который предполагает, что Perl использует UTF-8 внутри, неверен.

  5. Код, который предполагает, что ошибки кодирования всегда будут вызывать исключение, неверен.

  6. Код, который предполагает, что кодовые точки Perl ограничены 0x10_FFFF, неверен.

  7. Код, который предполагает, что вы можете установить $/ на то, что будет работать с любым допустимым разделителем строк, неверен.

  8. Код, который предполагает равенство в обоих направлениях при сложении слов, например lc(uc($s)) eq $s или uc(lc($s)) eq $s, полностью неверен и ошибочен. Учтите, что uc("σ") и uc("ς") оба являются "Σ", но lc("Σ") не может вернуть оба из них.

  9. Код, который предполагает, что каждая строчная кодовая точка имеет отдельную заглавную или наоборот, не работает. Например, "ª" - это строчная буква без прописных букв; тогда как "ᵃ" и "ᴬ" являются буквами, но они не являются строчными буквами; однако они оба являются строчными кодами без соответствующих заглавных версий. Понял? Они не \p{Lowercase_Letter}, несмотря на то, что они \p{Letter} и \p{Lowercase}.

  10. Код, который предполагает изменение регистра, не изменяет длину строки.

  11. Код, который предполагает, что есть только два случая, нарушен. Theres также заглавные буквы.

  12. Код, который предполагает, что только буквы имеют регистр, не работает. Оказывается, что помимо букв, цифры, символы и даже метки имеют регистр. Фактически, изменение корпуса может даже заставить что-то изменить его основную общую категорию, например, \p{Mark}, превращаясь в \p{Letter}. Он также может переключаться с одного сценария на другой.

  13. Код, который предполагает, что регистр никогда не зависит от локали, не работает.

  14. Код, который предполагает, что Unicode дает представление о локали POSIX, не работает.

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

  16. Код, который предполагает, что диакритические знаки \p{Diacritic} и знаки \p{Mark} - это одно и то же, не работает.

  17. Код, который предполагает, что \p{GC=Dash_Punctuation} охватывает столько же, сколько \p{Dash} не работает.

  18. Code that assumes dash, hyphens, и minuses are the same thing as each other, or that there is only one of each, is broken и wrong.

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

  20. Код, который предполагает, что все символы \p{Mark} занимают нулевые столбцы печати, не работает.

  21. Код, который предполагает, что символы, которые похожи друг на друга, похожи, поврежден.

  22. Код, который предполагает, что символы, которые не похожи друг на друга, не похожи, нарушается.

  23. Код, который предполагает, что существует ограничение на количество кодовых точек в строке, которым может соответствовать только один \X, является неправильным.

  24. Код, который предполагает, что \X никогда не может начинаться с символа \p{Mark}, неверен.

  25. Код, который предполагает, что \X никогда не может содержать два символа non- \p{Mark}, неверен.

  26. Код, который предполагает, что он не может использовать "\x{FFFF}", неверен.

  27. Код, который предполагает кодовую точку non- BMP, для которой требуются две кодовые единицы UTF-16 (суррогатные), будет кодироваться в два отдельных символа UTF-8, по одному на кодовую единицу, является неправильным. Это не так: он кодирует в одну кодовую точку.

  28. Код, который транскодирует из UTF-16 или UTF-32 с ведущими спецификациями в UTF-8, прерывается, если он помещает спецификацию в начало результирующего UTF-8. Это так глупо, что инженеру нужно убрать веки.

  29. Код, который предполагает, что CESU-8 является допустимой кодировкой UTF, неверен. Аналогично, код, который считает кодировку U + 0000 как "\xC0\x80" UTF-8, не работает и ошибается. Эти ребята также заслуживают лечения век.

  30. Код, в котором предполагается, что такие символы, как >, всегда указывает на право, а < всегда указывает на лево, они неверны, потому что на самом деле это не так.

  31. Код, который предполагает, что если вы сначала выведите символ X, а затем символ Y, то они будут отображаться как XY, и это неправильно. Иногда они этого не делают.

  32. Код, который предполагает, что ASCII достаточно хорош для правильного написания английского языка, глуп, недальновиден, неграмотен, сломлен, злой и неправильный. Долой свои головы! Если это кажется слишком экстремальным, мы можем пойти на компромисс: отныне они могут печатать только большим пальцем ноги от одной ноги. (Остальная часть будет приклеена воздуховодом.)

  33. Код, который предполагает, что все кодовые точки \p{Math} являются видимыми символами, неверен.

  34. Код, который предполагает, что \w содержит только буквы, цифры и подчеркивания, неверен.

  35. Код, который предполагает, что ^ и ~ являются знаками препинания, неверен.

  36. Код, который предполагает, что ü имеет умлаут, неверен.

  37. Код, который считает, что такие вещи, как содержат любые буквы в них, является неправильным.

  38. Код, который полагает, что \p{InLatin} совпадает с \p{Latin}, ужасно сломан.

  39. Код, который считает, что \p{InLatin} почти всегда полезен, почти наверняка неверен.

  40. Код, который полагает, что, учитывая $FIRST_LETTER как первую букву в некотором алфавите и $LAST_LETTER как последнюю букву в том же алфавите, что [${FIRST_LETTER}-${LAST_LETTER}] имеет какое-либо значение, почти всегда полное, неправильное и бессмысленное.

  41. Код, который считает, что чье-то имя может содержать только определенные символы, является глупым, оскорбительным и неправильным.

  42. Код, который пытается преобразовать Unicode в ASCII, не просто ошибочен, его исполнителю никогда не разрешат снова работать в программировании. Период. Я даже не уверен, что их даже нужно снова увидеть, так как это, очевидно, пока не принесло им много пользы.

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

  44. Код, который преобразует неизвестные символы в ?, сломан, глуп, повторяет и работает вопреки стандартной рекомендации, в которой говорится НЕ ДЕЛАТЬ ЭТО! RTFM, почему бы и нет.

  45. Код, который полагает, что он может надежно угадать кодировку немаркированного текстового файла, виновен в роковом соединении высокомерия и наивности, который исправит только молния Зевса.

  46. Код, который полагает, что вы можете использовать ширину 🐪 printf для дополнения и обоснования данных Unicode, неверен и неверен.

  47. Код, который полагает, что как только вы успешно создадите файл с заданным именем, при запуске ls или readdir в прилагаемом каталоге вы обнаружите, что файл с именем, под которым вы его создали, содержит ошибки, сломан и ошибочен. Хватит удивляться этому!

  48. Код, который считает UTF-16 кодированием с фиксированной шириной, глуп, сломан и ошибочен. Отзыв их лицензии на программирование.

  49. Код, который обрабатывает кодовые точки из одной плоскости, отличной от кода из любой другой плоскости, фактически является ошибочным и неверным. Возвращайся в школу.

  50. Код, который полагает, что такие вещи, как /s/i могут соответствовать только "S" или "s", поврежден и ошибочен. Вы будете удивлены.

  51. Код, который использует \PM\pM* для поиска кластеров графем вместо использования \X, неверен и неверен.

  52. Людей, которые хотят вернуться в мир ASCII, следует искренне поощрять к этому, и в честь их славного обновления им должна быть предоставлена бесплатная электрическая ручная пишущая машинка для всех их потребностей при вводе данных. Сообщения, отправленные им, следует отправлять по телеграфу по 40 символов в строке и доставлять вручную курьером. СТОП.


                        😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄 D


Я не знаю, сколько вы можете получить "Unicode по умолчанию в 🐪", чем то, что я написал. Ну, да, я понимаю: вы должны использовать Unicode::Collate и Unicode::LineBreak тоже. И, вероятно, больше.

Как видите, существует слишком много вещей, связанных с Юникодом, о которых вам действительно нужно беспокоиться, чтобы когда-либо существовала такая вещь, как "значение по умолчанию для Юникода".

То, что вы собираетесь обнаружить, так же, как мы делали это в § 5.8, что просто невозможно навязать все эти вещи в код, который не был разработан с самого начала, чтобы объяснить их. Твой благонамеренный эгоизм просто разрушил весь мир.

И даже после того, как вы это сделаете, по-прежнему есть критические проблемы, которые требуют большого количества размышлений, чтобы получить право. Там нет переключателя вы можете щелкнуть. Ничего, кроме мозга, а я имею в виду настоящий мозг, здесь не хватит. Theres чертовски много вещей, которые вы должны изучить. По модулю отступления к ручной пишущей машинке, вы просто не можете надеяться прокрасться в неведении. Это 21 век, и вы не можете желать Unicode умышленным невежеством.

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

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

Как только один пример, каноническое упорядочение вызовет некоторые реальные головные боли. 😭 "\x{F5}" , "o\x{303}" ' х, "o\x{303}\x{304}" и "o\x{304}\x{303}" ' ō̃ все соответствуют , но как в мире вы это сделаете? Это сложнее, чем кажется, но это то, что вам нужно учитывать. D

Если есть что-то, что я знаю о Perl, это то, что его биты Unicode делают и не делают, и вот что я обещаю вам: '̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲' 😞

Вы не можете просто изменить некоторые значения по умолчанию и получить плавный ход. Это правда, что я запускаю 🐪 с PERL_UNICODE установленным на "SA", но это все, и даже это в основном для командной строки. Для настоящей работы я прошёл все многочисленные шаги, описанные выше, и делаю это очень, ** очень ** осторожно.


  😈 ¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ ʻλɐp əɔᴉu ɐ əʌɐɥ ʻʞɔnl poo⅁ 😈

Ответ 2

Существует два этапа обработки текста Юникода. Во-первых, "как я могу ввести его и вывести его без потери информации". Во-вторых, "как обрабатывать текст в соответствии с соглашениями на локальном языке".

tchrist post охватывает оба, но вторая часть - это то, откуда приходит 99% текста в его сообщении. Большинство программ даже не обрабатывают ввод-вывод, поэтому важно понять, что прежде чем вы начнете беспокоиться о нормализации и сопоставлении.

Этот пост предназначен для решения этой первой проблемы

Когда вы читаете данные в Perl, все равно, какая именно кодировка. Он выделяет некоторую память и помещает туда байты. Если вы скажете print $str, он просто сбрасывает эти байты на ваш терминал, который, вероятно, настроен на то, чтобы предположить, что все, что написано на нем, это UTF-8, и ваш текст появляется.

Marvelous.

Кроме того, это не так. Если вы попытаетесь обработать данные как текст, вы увидите, что происходит что-то плохое. Вам нужно идти не дальше, чем length, чтобы увидеть, что Perl думает о вашей строке и о том, что вы думаете о своей строке, не согласны. Напишите один слой: perl -E 'while(<>){ chomp; say length }' и введите 文字化け, и вы получите 12... не правильный ответ, 4.

Это потому, что Perl предполагает, что ваша строка не является текстом. Вы должны сказать, что это текст, прежде чем он даст вам правильный ответ.

Это достаточно легко; модуль Encode имеет функции для этого. Общая точка входа Encode::decode (или use Encode qw(decode), конечно). Эта функция берет некоторую строку из внешнего мира (что мы будем называть "октетами", фантазией способа сказать "8-битные байты" ) и превращает ее в какой-то текст, который Perl поймет. Первый аргумент - это имя кодировки символов, например "UTF-8" или "ASCII" или "EUC-JP". Второй аргумент - строка. Возвращаемое значение - это скаляр Perl, содержащий текст.

(Существует также Encode::decode_utf8, который предполагает кодировку UTF-8.)

Если мы перепишем наш однострочный слой:

perl -MEncode=decode -E 'while(<>){ chomp; say length decode("UTF-8", $_) }'

Мы вводим 文字 化 け и получаем "4" в качестве результата. Успех.

Это, прямо там, является решением 99% проблем Unicode в Perl.

Ключ, всякий раз, когда какой-либо текст входит в вашу программу, вы должны его декодировать. Интернет не может передавать символы. Файлы не могут хранить символы. В базе данных нет символов. Есть только октеты, и вы не можете рассматривать октеты как символы в Perl. Вы должны декодировать закодированные октеты в символы Perl с помощью модуля Encode.

Другая половина проблемы - получение данных из вашей программы. Это легко; вы просто скажете use Encode qw(encode), решите, что будет кодировать ваши данные (UTF-8 для терминалов, которые понимают UTF-8, UTF-16 для файлов в Windows и т.д.), а затем выводят результат encode($encoding, $data) вместо просто выводя $data.

Эта операция преобразует символы Perl, на которые работает ваша программа, на октеты, которые могут использоваться внешним миром. Было бы намного проще, если бы мы могли просто отправлять персонажей через Интернет или на наши терминалы, но мы не можем: октеты. Поэтому нам нужно преобразовать символы в октеты, иначе результаты будут undefined.

Подводя итог: закодируйте все выходы и декодируйте все входы.

Теперь мы поговорим о трех проблемах, которые делают это немного сложной задачей. Первая - это библиотеки. Правильно ли они обрабатывают текст? Ответ... они пытаются. Если вы загрузите веб-страницу, LWP вернет вам результат в виде текста. Если вы вызываете правильный метод для результата, то есть (и это бывает decoded_content, а не content), который является только потоком октета, который он получил с сервера.) Драйверы базы данных могут быть шелушатся; если вы используете DBD:: SQLite только с Perl, это сработает, но если какой-нибудь другой инструмент поместил текст в качестве некоторой кодировки, отличной от UTF-8 в вашей базе данных... ну... это не будет правильно обработано пока вы не напишете код, чтобы правильно его обрабатывать.

Вывод данных обычно проще, но если вы видите "широкий символ в печати", то вы знаете, что где-то испортили кодировку. Это предупреждение означает "эй, вы пытаетесь пропустить персонажи Perl во внешний мир, и это не имеет никакого смысла". Ваша программа работает (потому что другой конец обычно обрабатывает необработанные символы Perl правильно), но он очень сломан и может перестать работать в любой момент. Исправьте его явным Encode::encode!

Вторая проблема - исходный код, кодированный UTF-8. Если вы не скажете use utf8 в верхней части каждого файла, Perl не будет предполагать, что ваш исходный код UTF-8. Это означает, что каждый раз, когда вы говорите что-то вроде my $var = 'ほげ', вы вводите мусор в свою программу, которая полностью разрушит все. Вам не нужно "использовать utf8", но если вы этого не сделаете, вы не должны использовать в своей программе символы, отличные от ASCII.

Третья проблема заключается в том, как Perl обрабатывает The Past. Давным-давно, не было такой вещи, как Unicode, и Perl предполагал, что все было латинским-1 текстом или двоичным. Поэтому, когда данные поступают в вашу программу, и вы начинаете рассматривать ее как текст, Perl обрабатывает каждый октет как символ Latin-1. Поэтому, когда мы попросили длину "文字 化 け", мы получили 12. Перл предположил, что мы работаем на латинской строке "æååã" (которая составляет 12 символов, некоторые из которых не печатаются).

Это называется "неявным обновлением", и это вполне разумная вещь, но это не то, что вы хотите, если ваш текст не является латинским-1. Вот почему критически важно явно декодировать ввод: если вы этого не сделаете, Perl будет, и он может сделать это неправильно.

Люди сталкиваются с проблемами, когда половина их данных является правильной символьной строкой, а некоторые по-прежнему являются двоичными. Perl будет интерпретировать часть, которая по-прежнему двоичная, как если бы она латинско-1 текст, а затем объединить ее с правильными символьными данными. Это заставит вас выглядеть так, как будто ваши персонажи правильно нарушили вашу программу, но на самом деле вы просто не исправили ее достаточно.

Вот пример: у вас есть программа, которая читает текстовый файл с кодировкой UTF-8, вы привязываете Unicode PILE OF POO к каждой строке, и вы распечатываете ее. Вы пишете его так:

while(<>){
    chomp;
    say "$_ 💩";
}

И затем запустите некоторые кодированные UTF-8 данные, например:

perl poo.pl input-data.txt

Он печатает данные UTF-8 с помощью poo в конце каждой строки. Отлично, моя программа работает!

Но нет, вы просто выполняете двоичную конкатенацию. Вы читаете октеты из файла, удаляя \n с помощью chomp и затем привязывая к байтам в представлении UTF-8 символа PILE OF POO. Когда вы пересматриваете свою программу для декодирования данных из файла и кодирования вывода, вы заметите, что вместо poo вы получаете мусор ( "ð ©" ). Это заставит вас поверить, что декодирование входного файла - это неправильная вещь. Это не так.

Проблема заключается в том, что poo неявно обновляется как latin-1. Если вы use utf8, чтобы сделать буквальный текст вместо двоичного, тогда он снова будет работать!

(Это проблема номер один, которую я вижу, когда помогаю людям с Юникодом. Они действительно правы, и это нарушило их программу. Что грустно в результатах undefined: у вас может быть рабочая программа в течение длительного времени, но когда вы начните ремонтировать его, он сломается. Не беспокойтесь: если вы добавляете в программу программы кодирования/декодирования, и это ломается, это просто означает, что у вас есть больше работы. В следующий раз, когда вы разрабатываете с Unicode в виду из начало, это будет намного проще!)

Это действительно все, что вам нужно знать о Perl и Unicode. Если вы сообщите Perl, что ваши данные, у него лучшая поддержка Unicode среди всех популярных языков программирования. Если вы предположите, что это будет волшебно знать, какой текст вы его кормите, однако, вы собираетесь бесполезно уничтожить свои данные. Просто потому, что ваша программа работает сегодня на вашем терминале UTF-8, не означает, что она будет работать завтра в кодированном файле UTF-16. Так что сделайте это безопасно сейчас и избавьте себя от головной боли, которая приведет к сбою данных ваших пользователей!

Легкая часть обработки Юникода - это входной и выходной данные кодирования. Жесткая часть - это поиск всех ваших входных и выходных данных и определение их кодировки. Но вот почему вы получаете большие деньги:)

Ответ 3

Мы все согласны с тем, что это сложная проблема по многим причинам, но именно поэтому стоит попытаться облегчить задачу для всех.

В CPAN недавно появился модуль utf8 :: all, который пытается "включить Unicode. Все это".

Как уже указывалось, вы не можете волшебным образом заставить всю систему (внешние программы, внешние веб-запросы и т.д.) Также использовать Unicode, но мы можем работать вместе, чтобы сделать разумные инструменты, облегчающие решение общих проблем. Вот почему мы программисты.

Если utf8 :: all не делает то, что вы считаете нужным, давайте улучшим его, чтобы сделать его лучше. Или позвольте сделать дополнительные инструменты, которые вместе могут удовлетворить людей различных потребностей, а также возможно.

'

Ответ 4

Я думаю, вы неправильно понимаете Unicode и его отношение к Perl. Независимо от того, каким образом вы храните данные, Unicode, ISO-8859-1 или многое другое, ваша программа должна знать, как интерпретировать байты он получает как вход (декодирование) и как представлять информацию, которую он хочет выводить (кодирование). Неправильно интерпретируйте эту интерпретацию, и вы разбираете данные. В вашей программе нет какой-то волшебной настройки по умолчанию, которая будет рассказывать вещам вне вашей программы, как действовать.

Вы думаете, что это сложно, скорее всего, потому что вы привыкли ко всему, что ASCII. Все, о чем вы должны думать, просто игнорировалось языком программирования и всеми вещами, с которыми ему приходилось взаимодействовать. Если бы все использовало ничего, кроме UTF-8, и у вас не было выбора, UTF-8 был бы таким же простым. Но не все использует UTF-8. Например, вы не хотите, чтобы ваш дескриптор ввода думал, что он получает октеты UTF-8, если это не так, и вы не хотите, чтобы ваши дескрипторы вывода были UTF-8, если считываемая вещь может обрабатывать UTF-8, Perl не имеет возможности узнать об этом. Вот почему вы программист.

Я не думаю, что Unicode в Perl 5 слишком сложный. Я думаю, что это страшно, и люди избегают этого. Там разница. С этой целью я поместил Unicode в Learning Perl, 6th Edition, и там много элементов Unicode в Эффективном программировании на Perl. Вы должны потратить время, чтобы узнать и понять Unicode и как это работает. В противном случае вы не сможете использовать его.

Ответ 5

Читая эту ветку, у меня часто складывается впечатление, что люди используют " UTF-8 " как синоним " Unicode ". Пожалуйста, сделайте различие между "кодовыми точками" Unicode, которые являются увеличенным родственником кода ASCII, и различными "кодировками" Unicode. И есть несколько из них, из которых UTF-8, UTF-16 и UTF-32 являются текущими, и еще несколько устарели.

Пожалуйста, UTF-8 (как и все другие кодировки) существует и имеет значение только для ввода или вывода. Внутренне, начиная с Perl 5.8.1, все строки хранятся как Unicode "Code-points". Правда, вы должны включить некоторые функции, которые были описаны выше.

Ответ 6

Там действительно ужасающее количество древнего кода в дикой природе, большая часть его в виде общих модулей CPAN. Я обнаружил, что должен быть достаточно осторожным, чтобы включить Unicode, если я использую внешние модули, на которые это может повлиять, и я все еще пытаюсь идентифицировать и исправлять некоторые ошибки, связанные с Unicode, в нескольких сценариях Perl, которые я использую регулярно (в частности, iTiVo плохо справляется с чем-либо, что не является 7-разрядным ASCII из-за проблем с перекодировкой).

Ответ 7

Вы должны включить функцию Unicode Strings, и это по умолчанию, если вы используете v5.14;

Вы не должны использовать Unicode-идентификаторы esp. для внешнего кода через utf8, поскольку они небезопасны в perl5, только cperl понял это правильно. Смотрите, например, http://perl11.org/blog/unicode-identifiers.html

Относительно utf8 для ваших файловых дескрипторов/потоков: вам нужно самостоятельно решить кодировку ваших внешних данных. Библиотека не может этого знать, и поскольку даже libc не поддерживает utf8, правильные данные utf8 встречаются редко. Там больше wtf8, вокруг окон аберрация utf8.

Кстати: Moose на самом деле не "Modern Perl", они просто похитили имя. Moose идеально подходит для постмодернистского Perl в стиле Ларри Уолла, смешанного с Bjarne Stroustrup, в стиле эклектики с правильным синтаксисом perl6, например, с использованием строк для имен переменных, синтаксиса ужасных полей и очень незрелой наивной реализации, которая в 10 раз медленнее, чем правильная реализация. cperl и perl6 - настоящие современные perls, где форма следует за функцией, а реализация сокращена и оптимизирована.