Почему современный 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.
8 ответов
: ℞:
Установите свой
PERL_UNICODE
Зависит отAS
, Это делает все сценарии Perl декодировать@ARGV
в виде строк UTF‑8 и устанавливает кодировку всех трех параметров stdin, stdout и stderr в UTF‑8. И то, и другое - глобальные, а не лексические последствия.В верхней части исходного файла (программа, модуль, библиотека,
do
хиккей), заметно утверждаю, что вы используете Perl версии 5.12 или выше через:use v5.12; # minimal for unicode string feature
use v5.14; # optimal for unicode string feature
Включите предупреждения, так как предыдущее объявление включает только ограничения и функции, а не предупреждения. Я также предлагаю превратить предупреждения Unicode в исключения, поэтому используйте обе эти строки, а не одну из них. Обратите внимание, что под v5.14,
utf8
Класс Warning содержит три других предупреждения, которые могут быть включены отдельно:nonchar
,surrogate
, а такжеnon_unicode
, Этим вы, возможно, захотите оказать больший контроль.use warnings;
use warnings qw( FATAL utf8 );
Объявите, что этот источник кодируется как UTF‑8. Хотя когда-то давно эта прагма делала другие вещи, теперь она служит одной единственной цели, а не другим:
use utf8;
Объявите, что все, что открывает файловые дескрипторы в этой лексической области, но не где-либо еще, означает, что этот поток закодирован в UTF-8, если вы не укажете иначе. Таким образом, вы не влияете на код другого модуля или другой программы.
use open qw( :encoding(UTF-8) :std );
Включить именованные символы через
\N{CHARNAME}
,use charnames qw( :full :short );
Если у тебя есть
DATA
обрабатывать, вы должны явно установить его кодировку. Если вы хотите, чтобы это был UTF‑8, то скажите:binmode(DATA, ":encoding(UTF-8)");
Конечно, нет конца другим вопросам, которые могут в конечном итоге вас заинтересовать, но их будет достаточно, чтобы приблизиться к государственной цели "заставить все просто работать с UTF-8", хотя и для несколько ослабленного смысла этих терминов.
Еще одна прагма, хотя она не связана с Unicode, это:
use autodie;
Настоятельно рекомендуется.
Сказать, что "Perl должен [ как-то! ] включить Unicode по умолчанию ", даже не задумываюсь о том, чтобы обойтись, говоря достаточно, чтобы быть хоть немного полезным в каком-то редком и единичном случае. Юникод - это намного больше, чем просто большой репертуар персонажей; Кроме того, все эти персонажи взаимодействуют по-разному.
Даже простейшие минимальные меры, которые, как кажется, некоторые (по мнению некоторых) думают, что они хотят, гарантированно сокрушат миллионы строк кода, кода, который не имеет шансов "обновить" до вашего изящного нового модного мира Brave New World.
Это намного сложнее, чем люди притворяются. За последние несколько лет я много думал об этом. Я хотел бы, чтобы мне показали, что я не прав. Но я так не думаю. Юникод существенно сложнее, чем модель, которую вы хотели бы навязать ему, и здесь есть сложность, которую вы никогда не сможете скрыть. Если вы попытаетесь, вы сломаете либо свой собственный, либо чужой код. В какой-то момент вы просто должны сломаться и узнать, что такое Unicode. Вы не можете притворяться, что это то, чем это не является.
делает все возможное, чтобы сделать Unicode простым, гораздо больше, чем все, что я когда-либо использовал. Если вы думаете, что это плохо, попробуйте что-нибудь другое на некоторое время. Затем вернитесь к: либо вы вернетесь в лучший мир, либо вы принесете то же самое с собой, чтобы мы могли использовать ваши новые знания, чтобы лучше справляться с этими вещами.
⸗
Как минимум, вот некоторые вещи, которые могут потребоваться для "включения Unicode по умолчанию", как вы это выразили:
Весь исходный код должен быть в UTF-8 по умолчанию. Вы можете получить это с
use utf8
или жеexport PERL5OPTS=-Mutf8
,DATA
ручка должна быть UTF-8. Вы должны будете сделать это на основе пакета, как вbinmode(DATA, ":encoding(UTF-8)")
,Программные аргументы скриптов должны пониматься как UTF-8 по умолчанию.
export PERL_UNICODE=A
, или жеperl -CA
, или жеexport PERL5OPTS=-CA
,Стандартные потоки ввода, вывода и ошибок должны по умолчанию использовать UTF-8.
export PERL_UNICODE=S
для всех них, илиI
,O
и / илиE
только для некоторых из них. Это какperl -CS
,Любые другие открытые дескрипторы должны рассматриваться как UTF-8, если не указано иное;
export PERL_UNICODE=D
или сi
а такжеo
для конкретных из них;export PERL5OPTS=-CD
должно сработать. Что делает-CSAD
для всех них.Покройте обе базы плюс все потоки, которые вы открываете
export PERL5OPTS=-Mopen=:utf8,:std
, Смотрите Uniquote.Вы не хотите пропустить ошибки кодирования UTF-8. Пытаться
export PERL5OPTS=-Mwarnings=FATAL,utf8
, И убедитесь, что ваши входные потоки всегдаbinmode
д:encoding(UTF-8)
не только:utf8
,Кодовые точки между 128–255 следует понимать как соответствующие кодовые точки Unicode, а не просто незаполненные двоичные значения.
use feature "unicode_strings"
или жеexport PERL5OPTS=-Mfeature=unicode_strings
, Что сделаюuc("\xDF") eq "SS"
а также"\xE9" =~ /\w/
, Простоexport PERL5OPTS=-Mv5.12
или лучше также получит это.Именованные символы Юникода по умолчанию не включены, поэтому добавьте
export PERL5OPTS=-Mcharnames=:full,:short,latin,greek
или что-то подобное. Смотрите Uninames и tcgrep.Вам почти всегда нужен доступ к функциям из стандарта
Unicode::Normalize
Модуль различных видов разложений.export PERL5OPTS=-MUnicode::Normalize=NFD,NFKD,NFC,NFKD
, а затем всегда запускать входящий материал через NFD и исходящий материал из NFC. Для них пока нет слоя ввода / вывода, но я вижу nfc, nfd, nfkd и nfkc.Сравнение строк при использовании
eq
,ne
,lc
,cmp
,sort
, & c & cc всегда неправы. Так что вместо@a = sort @b
, тебе нужно@a = Unicode::Collate->new->sort(@b)
, Можно добавить это к вашемуexport PERL5OPTS=-MUnicode::Collate
, Вы можете кэшировать ключ для бинарных сравнений.встроенные модули, такие как
printf
а такжеwrite
сделать что-то не так с данными Unicode. Вам нужно использоватьUnicode::GCString
модуль для первого и того, и другого, а такжеUnicode::LineBreak
Модуль, а также для последнего. Смотрите UWC и Unifmt.Если вы хотите, чтобы они считались целыми числами, вам придется запустить
\d+
захватывает черезUnicode::UCD::num
функция, потому что встроенный atoi (3) в настоящее время не достаточно умен.У вас будут проблемы с файловой системой. Некоторые файловые системы молча принудительно преобразуют в NFC; другие молча предписывают переход в NFD. А другие еще что-то делают. Некоторые даже полностью игнорируют этот вопрос, что приводит к еще большим проблемам. Таким образом, вы должны сделать свою собственную обработку NFC/NFD, чтобы оставаться в здравом уме.
Весь ваш код с участием
a-z
или жеA-Z
и такие должны быть изменены, в том числеm//
,s///
, а такжеtr///
, Это должно выделяться как кричащий красный флаг, что ваш код не работает. Но не ясно, как это должно измениться. Получить правильные свойства и понять их падеж сложнее, чем вы думаете. Я использую unichars и uniprops каждый день.Код, который использует
\p{Lu}
почти так же неправильно, как код, который использует[A-Za-z]
, Вам нужно использовать\p{Upper}
вместо этого, и знаю причину. Да,\p{Lowercase}
а также\p{Lower}
отличаются от\p{Ll}
а также\p{Lowercase_Letter}
,Код, который использует
[a-zA-Z]
еще хуже. И это не может использовать\pL
или же\p{Letter}
; это нужно использовать\p{Alphabetic}
, Знаете, не все алфавиты являются буквами!Если вы ищете переменные с
/[\$\@\%]\w+/
тогда у тебя проблемы. Вам нужно искать/[\$\@\%]\p{IDS}\p{IDC}*/
и даже это не думает о знаках препинания или пакетных переменных.Если вы проверяете наличие пробелов, то вы должны выбрать между
\h
а также\v
в зависимости. И вы никогда не должны использовать\s
, так как это не значит[\h\v]
, вопреки распространенному мнению.Если вы используете
\n
для границы линии, или даже\r\n
тогда вы делаете это неправильно. Вы должны использовать\R
, что не то же самое!Если вы не знаете, когда и нужно ли вызывать Unicode:: Stringprep, вам лучше научиться.
Сравнение без учета регистра должно проверять, являются ли две вещи одинаковыми буквами, независимо от их диакритики и тому подобного. Самый простой способ сделать это - использовать стандартный модуль Unicode:: Collate.
Unicode::Collate->new(level => 1)->cmp($a, $b)
, Это такжеeq
методы и тому подобное, и вы, вероятно, должны узнать оmatch
а такжеsubstr
методы тоже. Они имеют явные преимущества перед встроенными.Иногда этого все еще недостаточно, и вместо этого вам нужен модуль http://search.cpan.org/perldoc?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", " ð")
ложно Точно так же "ае" и "æ" являютсяeq
если вы не используете локали или английскую, но в исландской локали они разные. Что теперь? Это сложно, говорю тебе. Вы можете поиграть с ucsort, чтобы проверить некоторые из этих вещей.Рассмотрим, как сопоставить шаблон CVCV (согласный, гласный, согласный, гласный) в строке " niño ". Его форма NFD - которую вы чертовски хорошо запомнили, чтобы ее вставить - становится "nin\x{303}o". Теперь, что ты собираешься делать? Даже притворяясь, что гласная
[aeiou]
(что, кстати, неправильно), вы не сможете сделать что-то вроде(?=[aeiou])\X)
либо потому, что даже в NFD кодовая точка типа 'ø' не разлагается! Тем не менее, он будет проверяться равным "о", используя сравнение UCA, которое я только что показал вам. Вы не можете полагаться на НФД, вы должны полагаться на УЦА.
И это еще не все. Есть миллион ошибочных предположений о Unicode. Пока они не поймут эти вещи, их код будет нарушен.
Код, который предполагает, что он может открыть текстовый файл без указания кодировки, поврежден.
Код, который предполагает кодировку по умолчанию, является неким родным кодированием платформы.
Код, предполагающий, что веб-страницы на японском или китайском языке занимают меньше места в UTF‑16, чем в UTF‑8, неверен.
Код, который предполагает, что Perl использует UTF-8 внутри, неверен.
Код, который предполагает, что ошибки кодирования всегда будут вызывать исключение, неверен.
Код, который предполагает, что кодовые точки Perl ограничены 0x10_FFFF, неверен.
Код, который предполагает, что вы можете установить
$/
что-то, что будет работать с любым допустимым разделителем строк, неверно.Код, который предполагает равенство в обоих направлениях при сложении слов, например
lc(uc($s)) eq $s
или жеuc(lc($s)) eq $s
, полностью сломан и не прав. Считайте, чтоuc("σ")
а такжеuc("ς")
оба"Σ"
, ноlc("Σ")
не может вернуть оба из них.Код, который предполагает, что каждая строчная кодовая точка имеет отдельную заглавную или наоборот, не работает. Например,
"ª"
строчная буква без прописных букв; тогда как оба"ᵃ"
а также"ᴬ"
являются буквами, но они не строчные буквы; однако они оба являются строчными кодами без соответствующих заглавных версий. Понял? Они не\p{Lowercase_Letter}
несмотря на то, что оба\p{Letter}
а также\p{Lowercase}
,Код, который предполагает изменение регистра, не меняет длину строки.
Код, который предполагает, что есть только два случая, нарушен. Там также заглавные буквы.
Код, который предполагает, что только буквы имеют регистр, не работает. Оказывается, что помимо букв, цифры, символы и даже метки имеют регистр. На самом деле, изменение дела может даже заставить что-то изменить его основную общую категорию, например
\p{Mark}
превращается в\p{Letter}
, Это также может заставить его переключаться с одного сценария на другой.Код, который предполагает, что регистр никогда не зависит от локали, нарушается.
Код, который предполагает, что Unicode дает представление о языковых стандартах POSIX, не работает.
Кодекс, который предполагает, что вы можете удалить диакритические знаки, чтобы получить базовые буквы ASCII, является злом, все же сломанным, поврежденным мозгом, неправильным и оправданием смертной казни.
Кодекс, который предполагает, что диакритические знаки
\p{Diacritic}
и отметки\p{Mark}
Это то же самое, что сломано.Код, который предполагает
\p{GC=Dash_Punctuation}
охватывает столько, сколько\p{Dash}
сломано.Код, который предполагает тире, дефисы и минусы - это то же самое, что и друг друга, или то, что существует только один из них, не работает и ошибается.
Код, который предполагает, что каждая кодовая точка занимает не более одного столбца печати, поврежден.
Кодекс, который предполагает, что все
\p{Mark}
символы занимают ноль, печать столбцов нарушена.Код, который предполагает, что символы, которые похожи друг на друга , похожи, сломан.
Код, который предполагает, что символы, которые не похожи друг на друга, не похожи, нарушается.
Код, который предполагает, что есть ограничение на количество кодовых точек в строке, которое только один
\X
может совпадать неправильно.Код, который предполагает
\X
никогда не может начать с\p{Mark}
персонаж не прав.Код, который предполагает, что
\X
никогда не может держать два\p{Mark}
персонажи не правы.Код, который предполагает, что он не может использовать
"\x{FFFF}"
неправильно.Код, предполагающий кодовую точку, отличную от BMP, для которой требуются две кодовые единицы UTF-16 (суррогатные), будет кодироваться в два отдельных символа UTF-8, по одному на кодовую единицу, является неправильным. Это не так: он кодирует в одну кодовую точку.
Код, который транскодирует из UTF-16 или UTF-32 с ведущими спецификациями в UTF-8, прерывается, если он помещает спецификацию в начало результирующего UTF-8. Это так глупо, что инженеру нужно убрать веки.
Код, который предполагает, что CESU-8 является допустимой кодировкой UTF, неверен. Аналогично, код, который считает кодирование U + 0000 как
"\xC0\x80"
это UTF-8 сломан и не прав. Эти ребята также заслуживают лечения век.Код, который предполагает символы, такие как
>
всегда указывает на право и<
всегда указывает налево неправильно - потому что они на самом деле нет.Код, который предполагает, что вы впервые выводите символ
X
а затем характерY
, что те будут отображаться какXY
неправильно. Иногда они этого не делают.Код, который предполагает, что ASCII достаточно хорош для правильного написания английского, глуп, недальновиден, неграмотен, сломлен, злой и неправильный. Долой их головы! Если это кажется слишком экстремальным, мы можем пойти на компромисс: отныне они могут печатать только большим пальцем на одной ноге (остальные все еще могут быть прислонены).
Кодекс, который предполагает, что все
\p{Math}
Кодовые точки видимых символов неверны.Код, который предполагает
\w
содержит только буквы, цифры и подчеркивания неверно.Код, который предполагает, что
^
а также~
являются знаки препинания неправильно.Код, который предполагает, что
ü
Умлаут это неправильно.Кодекс, который считает, что такие вещи, как
₨
содержать какие-либо буквы в них неправильно.Кодекс, который верит
\p{InLatin}
такой же как\p{Latin}
отвратительно сломленКодекс, который считает, что
\p{InLatin}
почти всегда полезно, почти наверняка неправильно.Кодекс, который считает, что данный
$FIRST_LETTER
в качестве первой буквы в некотором алфавите и$LAST_LETTER
как последняя буква в том же алфавите, что[${FIRST_LETTER}-${LAST_LETTER}]
имеет какое-либо значение, почти всегда почти полное, ошибочное и бессмысленное.Код, который считает, что чье-то имя может содержать только определенные символы, является глупым, оскорбительным и неправильным.
Код, который пытается преобразовать Unicode в ASCII, не просто ошибочен, его исполнителю никогда не разрешат снова работать в программировании. Период. Я даже не уверен, что их даже нужно снова увидеть, так как это, очевидно, пока не принесло им много пользы.
Код, который считает, что есть какой-то способ притвориться, что кодировки текстовых файлов не существуют, сломан и опасен. С таким же успехом можно высунуть и другой глаз.
Код, который преобразует неизвестные символы в
?
сломан, глуп, бредит, и идет вразрез со стандартной рекомендацией, которая говорит, что не делать этого! RTFM почему бы и нет.Код, который полагает, что он может надежно угадать кодировку немаркированного текстового файла, виновен в роковом соединении высокомерия и наивности, который исправит только молния Зевса.
Код, который считает, что вы можете использовать
printf
ширина, чтобы дополнить и оправдать данные Unicode, неверна и неверна.Код, который полагает, что после успешного создания файла с заданным именем, при запуске
ls
или жеreaddir
в прилагаемом каталоге вы обнаружите, что файл с именем, под которым вы его создали, содержит ошибки, сломан и ошибочен. Хватит удивляться этому!Код, который полагает, что UTF-16 является кодированием с фиксированной шириной, глуп, сломан и ошибочен. Отзыв их лицензии на программирование.
Код, который обрабатывает кодовые точки из одной плоскости, отличные от кодов из любой другой плоскости, ipso facto сломан и ошибочен. Идти обратно в школу.
Код, который считает, что такие вещи, как
/s/i
может только соответствовать"S"
или же"s"
сломан и не прав. Вы будете удивлены.Код, который использует
\PM\pM*
чтобы найти кластеры графемы вместо того, чтобы использовать\X
сломан и не прав.Людей, которые хотят вернуться в мир ASCII, следует искренне поощрять к этому, и в честь их славного обновления им должна быть предоставлена бесплатная электрическая ручная пишущая машинка для всех их потребностей при вводе данных. Сообщения, отправленные им, следует отправлять по телеграфу по 40 символов в строке и доставлять вручную курьером. СТОП.
⸗ ⸗
Мой собственный шаблон в эти дни имеет тенденцию выглядеть следующим образом:
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 stackdumped exceptions
# *unless* we're in an try block, in which
# case just generate a clucking stackdump instead
local $SIG{__WARN__} = sub {
if ($^S) { cluck "Trapped warning: @_" }
else { confess "Deadly warning: @_" }
};
while (<>) {
chomp;
$_ = NFD($_);
...
} continue {
say NFC($_);
}
__END__
Я не знаю, сколько вы можете получить "по умолчанию в Юникоде", чем то, что я написал. Ну, да, я делаю: вы должны использовать Unicode::Collate
а также Unicode::LineBreak
, тоже. И, вероятно, больше.
Как видите, существует слишком много вещей, связанных с Юникодом, о которых вам действительно нужно беспокоиться, чтобы когда-либо существовала такая вещь, как "значение по умолчанию для Юникода".
То, что вы собираетесь обнаружить, так же, как мы делали это в 5.8, что просто невозможно навязать все эти вещи в код, который не был разработан с самого начала, чтобы объяснить их. Твой благонамеренный эгоизм просто сломал весь мир.
И даже после того, как вы это сделаете, есть все еще критические проблемы, которые требуют большого количества размышлений, чтобы получить право. Там нет переключателя вы можете щелкнуть. Ничего, кроме мозга, а я имею в виду настоящий мозг, здесь не хватит. Есть чертовски много вещей, которые ты должен изучить. По модулю отступления к ручной пишущей машинке вы просто не можете надеяться пробраться в неведении. Это 21 век, и вы не можете желать Unicode умышленным невежеством.
Вы должны изучить это. Период. Никогда не будет так просто, что "все просто работает", потому что это гарантирует, что многие вещи не работают - что лишает законной силы предположение, что когда-либо может быть способ "заставить все это работать".
Возможно, вам удастся получить несколько разумных значений по умолчанию для очень немногих и очень ограниченных операций, но не думая о вещах намного больше, чем я думаю, у вас есть.
Как только один пример, каноническое упорядочение вызовет некоторые реальные головные боли. "\x{F5}"
'х', "o\x{303}"
'х', "o\x{303}\x{304}"
'ȭ' и "o\x{304}\x{303}"
"ō̃" должно соответствовать "õ", но как в мире вы это сделаете? Это сложнее, чем кажется, но это то, что вам нужно учитывать.
Если есть что-то, что я знаю о Perl, это то, что его биты Unicode делают и не делают, и я обещаю вам следующее: "̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲"
You cannot just change some defaults and get smooth sailing. It's true that I run with PERL_UNICODE
установлен в "SA"
, but that's all, and even that is mostly for command-line stuff. For real work, I go through all the many steps outlined above, and I do it very, ** very** carefully.
¡ƨdləɥ ƨᴉɥʇ ədoɥ puɐ ʻλɐp əɔᴉu ɐ əʌɐɥ ʻʞɔnl poo⅁
Есть две стадии обработки текста Unicode. Первый - "как я могу ввести его и вывести без потери информации". Второе - "как мне относиться к тексту в соответствии с местными языковыми соглашениями".
пост tchrist покрывает оба, но вторая часть - то, откуда 99% текста в его посте взято. Большинство программ даже не обрабатывают ввод / вывод правильно, поэтому важно понять это, прежде чем вы даже начнете беспокоиться о нормализации и сопоставлении.
Этот пост призван решить эту первую проблему
Когда вы читаете данные в Perl, не важно, какая это кодировка. Он выделяет некоторую память и хранит байты там. Если вы говорите print $str
, он просто сбрасывает эти байты на ваш терминал, который, вероятно, настроен на то, чтобы предположить, что все, что записано в него, является UTF-8, и ваш текст отображается.
Изумительный.
За исключением того, что это не так. Если вы попытаетесь обработать данные как текст, вы увидите, что происходит что-то плохое. Вам не нужно идти дальше, чем 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, над которыми работает ваша программа, в октеты, которые могут использоваться внешним миром. Было бы намного проще, если бы мы могли просто отправлять символы через Интернет или на наши терминалы, но мы не можем: только октеты. Поэтому мы должны конвертировать символы в октеты, иначе результаты не определены.
Подводя итог: закодировать все выходы и декодировать все входы.
Теперь поговорим о трех вопросах, которые делают это немного сложным. Первое - это библиотеки. Правильно ли они обрабатывают текст? Ответ... они пытаются. Если вы загрузите веб-страницу, 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 обрабатывает прошлое. Давным-давно не было такой вещи, как Unicode, и Perl предполагал, что все было латинским-1 текстовым или двоичным. Поэтому, когда данные поступают в вашу программу и вы начинаете обрабатывать их как текст, Perl обрабатывает каждый октет как символ латинского алфавита 1. Вот почему, когда мы спросили длину "文字化け", мы получили 12. Perl предположил, что мы работаем со строкой Latin-1 "æååã" (которая состоит из 12 символов, некоторые из которых не печатаются).
Это называется "неявным обновлением", и это вполне разумно, но это не то, что вам нужно, если ваш текст не Latin-1. Вот почему так важно явно декодировать ввод: если вы этого не сделаете, Perl сделает это, и он может сделать это неправильно.
Люди сталкиваются с проблемами, когда половина их данных является правильной символьной строкой, а некоторые все еще двоичными. Perl интерпретирует двоичную часть, как будто это текст Latin-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
сделать буквальный текст вместо двоичного, тогда он снова заработает!
(Это проблема номер один, которую я вижу, когда помогаю людям с Unicode. Они правильно расставались, и это нарушало их программу. Вот что печально в отношении неопределенных результатов: у вас может быть рабочая программа в течение длительного времени, но когда вы начинаете ее восстанавливать, это ломает. Не волнуйтесь, если вы добавляете операторы кодирования / декодирования в свою программу, и это ломается, это просто означает, что у вас есть больше работы. В следующий раз, когда вы с самого начала будете проектировать с Unicode, это будет намного легче!)
Это действительно все, что вам нужно знать о Perl и Unicode. Если вы скажете Perl, какие у вас данные, у вас будет лучшая поддержка Unicode среди всех популярных языков программирования. Если вы предполагаете, что он будет волшебным образом знать, какой тип текста вы подаете, тем не менее, тогда вы безвозвратно уничтожите свои данные. Тот факт, что ваша программа работает сегодня на вашем терминале UTF-8, не означает, что она будет работать завтра для файла в кодировке UTF-16. Поэтому сделайте это сейчас безопасным и избавьте себя от головной боли, связанной с уничтожением данных ваших пользователей!
Простая часть обработки Unicode - это кодирование вывода и декодирование ввода. Сложная часть - найти все ваши входные и выходные данные и определить, какая это кодировка. Но именно поэтому вы получаете большие деньги:)
Мы все согласны с тем, что это сложная проблема по многим причинам, но именно поэтому мы стараемся облегчить задачу для всех.
В CPAN недавно появился модуль utf8:: all, который пытается "включить Unicode. Все это".
Как уже указывалось, вы не можете волшебным образом заставить всю систему (внешние программы, внешние веб-запросы и т. Д.) Также использовать Unicode, но мы можем работать вместе, чтобы сделать разумные инструменты, облегчающие решение общих проблем. Вот почему мы программисты.
Если utf8:: all не делает то, что вы считаете нужным, давайте улучшим его, чтобы сделать его лучше. Или давайте создадим дополнительные инструменты, которые вместе могут максимально удовлетворить различные потребности людей.
`
Я думаю, вы неправильно понимаете 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, и в Effective Perl Programming есть много вещей, связанных с Unicode. Вы должны потратить время, чтобы изучить и понять Unicode и как он работает. В противном случае вы не сможете использовать его эффективно.
Читая эту ветку, у меня часто складывается впечатление, что люди используют " UTF-8" как синоним " Unicode". Пожалуйста, сделайте различие между "кодовыми точками" Unicode, которые являются увеличенным родственником кода ASCII, и различными "кодировками" Unicode. И есть несколько из них, из которых UTF-8, UTF-16 и UTF-32 являются текущими, и еще несколько устарели.
Пожалуйста, UTF-8 (как и все другие кодировки) существует и имеет значение только для ввода или вывода. Внутренне, начиная с Perl 5.8.1, все строки хранятся как Unicode "Code-points". Правда, вы должны включить некоторые функции, которые были описаны выше.
В дикой природе существует действительно ужасающее количество древнего кода, большая часть которого представлена в виде обычных модулей CPAN. Я обнаружил, что должен быть довольно осторожным при включении Unicode, если я использую внешние модули, на которые он может повлиять, и все еще пытаюсь выявить и исправить некоторые ошибки Unicode в нескольких Perl-скриптах, которые я регулярно использую (в частности, происходит сбой iTiVo плохо на всем, что не является 7-битным ASCII из-за проблем с транскодированием).
Вы должны включить функцию 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 в стиле Ларри Уолла, смешанного с стилем Бьярна Страуструпа, с эклектической аберрацией правильного синтаксиса perl6, например, использованием строк для имен переменных, синтаксиса ужасных полей и очень незрелой наивной реализацией, которая в 10 раз медленнее, чем правильная реализация. cperl и perl6 - настоящие современные perls, где форма следует за функцией, а реализация сокращена и оптимизирована.
Речь идет не о Perl как таковом , нет, но я демонстрирую здесь современность Python, которая, как мне кажется, говорит сама за себя (возможно, чтобы быть более точным и актуальным, мой ответ: «потому что никто больше не должен использовать Perl-Python более читабелен и удобочитаем; он более элегантен, красивее, мощнее, популярнее и легко обрабатывает все кодировки Unicode / utf8 [по состоянию на последнее время]"):
#!/usr/bin/env/python3.10
import io
with io.open("all_utf-8.txt", "w", encoding="utf8") as f:
for n in range(50,150000,5):
try:
i = chr(n)
if i.isprintable():
print(f"{i}", end="", file=f)
if n % 66 == 0:
print(file=f)
except UnicodeError:
pass
(SO сообщения, по-видимому, ограничены 30 000 символов; следовательно, skip = 5)
"all_utf-8.txt":
27<AFKPUZ_dinsx}¥ª¯´¹¾ÃÈÍÒ×ÜáæëðõúÿĄĉĎēĘĝĢħĬıĶĻŀŅŊ
ŏŔřŞţŨŭŲŷżƁƆƋƐƕƚƟƤƩƮƳƸƽǂLJnjǑǖǛǠǥǪǯǴǹǾȃȈȍȒȗȜȡȦȫȰȵȺȿɄɉɎɓɘɝɢɧɬɱɶɻʀʅʊʏʔ
ʙʞʣʨʭʲʷʼˁˆˋː˕˚˟ˤ˩ˮ˳˸˽̴̛̖̠̥̪̯̹͈͍̂̇̌̑̾̓͒͗ͦͫ͜͡Ͱ͵ͺͿ΄ΉΎΓΘΝΧάαζλπυϊϏϔϙϞ
ϣϨϭϲϷϼЁІЋАЕКПФЩЮгинтчьёіћѠѥѪѯѴѹѾ҃҈ҍҒҗҜҡҦҫҰҵҺҿӄӉӎӓӘӝӢӧӬӱӶӻԀԅԊԏԔԙԞԣԨ
ԭԲԷԼՁՆՋՐՕ՚՟դթծճոսւևִֹ֑֖֛֥֪֠֯־׃גחלסצװ؉؎ؘؓآاجرضػـمئُٙٞ٣٨٭ٲ
ٷټځچڋڐڕښڟڤکڮڳڸڽۂۇیۑۖۛ۠ۥ۪ۯ۴۹۾܃܈܍ܒܗܜܡܦܫ݄ܰܵܺܿ݉ݎݓݘݝݢݧݬݱݶݻހޅފޏޔޙޞޣިޭ
ሂሇሌ
ሑሖማሠሥሪሯሴሹሾቃቈቍቒቜቡቦቫተትቺቿኄናኘኝኢኧኬኻዀዅዊዏዔዙዞዣየይዲዷዼጁጆጋጐጕጚጟጤጩጮጳጸጽፂፇፌፑፖ
፠፥፪፯፴፹ᎃᎈᎍ᎒᎗ᎡᎦᎫᎰᎵᎺᎿᏄᏉᏎᏓᏘᏝᏢᏧᏬᏱᏻ᐀ᐅᐊᐏᐔᐙᐞᐣᐨᐭᐲᐷᐼᑁᑆᑋᑐᑕᑚᑟᑤᑩᑮᑳᑸᑽᒂᒇᒌᒑᒖᒛᒠ
ᒥᒪᒯᒴᒹᒾᓃᓈᓍᓒᓗᓜᓡᓦᓫᓰᓵᓺᓿᔄᔉᔎᔓᔘᔝᔢᔧᔬᔱᔶᔻᕀᕅᕊᕏᕔᕙᕞᕣᕨᕭᕲᕷᕼᖁᖆᖋᖐᖕᖚᖟᖤᖩᖮᖳᖸᖽᗂᗇᗌᗑᗖᗛᗠᗥᗪ
ᗯᗴᗹᗾᘃᘈᘍᘒᘗᘜᘡᘦᘫᘰᘵᘺᘿᙄᙉᙎᙓᙘᙝᙢᙧᙬᙱᙶᙻᚅᚊᚏᚔᚙᚣᚨᚭᚲᚷᚼᛁᛆᛋᛐᛕᛚᛟᛤᛩᛮᛳᛸᜂᜇᜌᜑᜠᜥᜪᜯ᜴
ᝃᝈᝍᝒᝡᝦᝫᝰងញណនមឝអឧឬឱាុៀៅ៊៏។៙៣៨៲៷᠁᠆᠋᠐᠕ᠤᠩᠮᠳᠸᠽᡂᡇᡌᡑᡖᡛᡠᡥᡪᡯᡴ
ᢃᢈᢍᢒᢗᢜᢡᢦᢰᢵᢺᢿᣄᣉᣎᣓᣘᣝᣢᣧᣬᣱᤀᤅᤊᤏᤔᤙᤞᤣᤨᤲᤷ᥆᥋ᥐᥕᥚᥟᥤᥩᥳᦂᦇᦌᦑᦖᦛᦠᦥᦪᦴᦹᦾᧃᧈ
᧒᧗᧡᧦᧫᧰᧵᧺᧿ᨄᨉᨎᨓᨘᨢᨧᨬᨱᨶᨻᩀᩅᩊᩏᩔᩙᩞᩣᩨᩭᩲ᩷᩼᪁᪆᪐᪕᪤᪩᪸᪽᪳ᬃᬈᬍᬒ
ᬗᬜᬡᬦᬫᬰᬵᬺᬿ᭄ᭉ᭓᭘᭝᭢᭧᭬᭱᭶᭻ᮀᮅᮊᮏᮔᮙᮞᮣᮨᮭ᮲᮷ᮼᯁᯆᯋᯐᯕᯚᯟᯤᯩᯮ᯳᯽ᰂᰇᰌᰑᰖᰛᰠᰥᰪᰯᰴ᰾᱃᱈ᱍ᱒᱗ᱜ
ᱡᱦᱫᱰᱵᱺ᱿ᲄᲓᲘᲝᲢᲧᲬᲱᲶ᳀᳅᳔᳣᳨᳙᳞᳭ᳲ᳷ᴁᴆᴋᴐᴕᴚᴟᴤᴩᴮᴳᴸᴽᵂᵇᵌᵑᵖᵛᵠᵥᵪᵯᵴᵹᵾᶃᶈᶍᶒᶗᶜᶡᶦ
ᶫᶰᶵᶺᶿ᷎᷄᷉ᷓᷘᷝᷢᷧᷬᷱ᷻᷶ḀḅḊḏḔḙḞḣḨḭḲḷḼṁṆṋṐṕṚṟṤṩṮṳṸṽẂẇẌẑẖẛẠấẪắẴẹẾểỈọỒỗỜỡỦừỰ
ỵỺỿἄἉἎἓἘἝἢἧἬἱἶἻὀὅὊὔὙὣὨὭὲίὼᾁᾆᾋᾐᾕᾚᾟᾤᾩᾮᾳᾸ᾽ῂῇῌῑῖΊῠῥῪ`ῴΌ῾‒‗“‡…‰‵›
‿⁄⁉⁎⁓⁘⁝ⁱ⁶⁻₀₅₊ₔₙ₣₨₭₲₷₼⃚⃐⃕⃟⃤⃮⃩ℂℇℌℑ№ℛ℠℥Kℯℴℹℾ⅃ⅈ⅍⅒⅗⅜ⅡⅦⅫⅰⅵⅺⅿↄ
↉↓↘↝↢↧↬↱↶↻⇀⇅⇊⇏⇔⇙⇞⇣⇨⇭⇲⇷⇼∁∆∋∐∕√∟∤∩∮∳∸∽≂≇≌≑≖≛≠≥≪≯≴≹≾⊃⊈⊍⊒⊗⊜⊡⊦⊫⊰⊵⊺⊿⋄⋉⋎
⋓⋘⋝⋢⋧⋬⋱⋶⋻⌀⌅⌊⌏⌔⌙⌞⌣⌨⌭⌲⌷⌼⍁⍆⍋⍐⍕⍚⍟⍤⍩⍮⍳⍸⍽⎂⎇⎌⎑⎖⎛⎠⎥⎪⎯⎴⎹⎾⏃⏈⏍⏒⏗⏜⏡⏦⏫⏰⏵⏺⏿␄␉␎␓␘
␝␢⑀⑅⑊④⑨⑭⑲⑷⑼⒁⒆⒋⒐⒕⒚⒟⒤⒩⒮⒳ⒸⒽⓂⓇⓌⓑⓖⓛⓠⓥ⓪⓯⓴⓹⓾┃┈┍┒┗├┡┦┫┰┵┺┿╄╉╎╓╘╝╢
╧╬╱╶╻▀▅▊▏▔▙▞▣▨▭▲▷▼◁◆○◐◕◚◟◤◩◮◳◸◽☂☇☌☑☖☛☠☥☪☯☴☹☾♃♈♍♒♗♜♡♦♫♰♵♺♿⚄⚉⚎⚓⚘⚝⚢⚧⚬
⚱⚶⚻⛀⛅⛊⛏⛔⛙⛞⛣⛨⛭⛲⛷⛼✁✆✋✐✕✚✟✤✩✮✳✸✽❂❇❌❑❖❛❠❥❪❯❴❹❾➃➈➍➒➗➜➡➦➫➰➵➺➿⟄⟉⟎⟓⟘⟝⟢⟧⟬⟱⟶
⟻⠀⠅⠊⠏⠔⠙⠞⠣⠨⠭⠲⠷⠼⡁⡆⡋⡐⡕⡚⡟⡤⡩⡮⡳⡸⡽⢂⢇⢌⢑⢖⢛⢠⢥⢪⢯⢴⢹⢾⣃⣈⣍⣒⣗⣜⣡⣦⣫⣰⣵⣺⣿⤄⤉⤎⤓⤘⤝⤢⤧⤬⤱⤶⤻⥀
⥅⥊⥏⥔⥙⥞⥣⥨⥭⥲⥷⥼⦁⦆⦋⦐⦕⦚⦟⦤⦩⦮⦳⦸⦽⧂⧇⧌⧑⧖⧛⧠⧥⧪⧯⧴⧹⧾⨃⨈⨍⨒⨗⨜⨡⨦⨫⨰⨵⨺⨿⩄⩉⩎⩓⩘⩝⩢⩧⩬⩱⩶⩻⪀⪅⪊
⪏⪔⪙⪞⪣⪨⪭⪲⪷⪼⫁⫆⫋⫐⫕⫚⫟⫤⫩⫮⫳⫸⫽⬂⬇⬌⬑⬖⬛⬠⬥⬪⬯⬴⬹⬾⭃⭈⭍⭒⭗⭜⭡⭦⭫⭰⭺⭿⮄⮉⮎⮓⮘⮝⮢⮧⮬⮱⮶⯀⯅⯊⯏⯭ⰁⰆⰋ%*/49>CHMRW\
afkpuz£₩→𐀄𐀉𐀎𐀓𐀘𐀝𐀢𐀬𐀱𐀶𐁀𐁅𐁊𐁔𐁙𐂁𐂆
𐂋𐂐𐂕𐂚𐂟𐂤𐂩𐂮𐂳𐂸𐂽𐃂𐃇𐃌𐃑𐃖𐃛𐃠𐃥𐃪𐃯𐃴𐃹𐄈𐄍𐄒𐄗𐄜𐄡𐄦𐄫𐄰𐄺𐄿𐅄𐅉𐅎𐅓𐅘𐅝𐅢𐅧𐅬𐅱𐅶𐅻𐆀𐆅𐆊𐆔𐆙𐇐
𐇕𐇚𐇟𐇤𐇩𐇮𐇳𐇸𐇽𐊄𐊉𐊎𐊓𐊘𐊢𐊧𐊬𐊱𐊶𐊻𐋀𐋅𐋊𐋏𐋣𐋨𐋭𐋲𐋷𐌁𐌆𐌋𐌐𐌕𐌚
𐌟𐌮𐌳𐌸𐌽𐍂𐍇𐍑𐍖𐍛𐍠𐍥𐍪𐍯𐍴𐍹𐎃𐎈𐎍𐎒𐎗𐎜𐎡𐎦𐎫𐎰𐎵𐎺𐎿𐏉𐏎𐏓𐐀𐐅𐐊𐐏𐐔𐐙𐐞𐐣𐐨𐐭𐐲𐐷𐐼𐑁𐑆𐑋𐑐𐑕𐑚𐑟𐑤
𐑩𐑮𐑳𐑸𐑽𐒂𐒇𐒌𐒑𐒖𐒛𐒠𐒥𐒴𐒹𐒾𐓃𐓈𐓍𐓒𐓜𐓡𐓦𐓫𐓰𐓵𐓺𐔄𐔉𐔎𐔓𐔘𐔝𐔢𐔧𐔱𐔶𐔻𐕀𐕅𐕊𐕏𐕔𐕙𐕞𐕣
𐘃𐘈𐘍𐘒𐘗𐘜𐘡𐘦𐘫𐘰𐘵𐘺𐘿𐙄𐙉𐙎𐙓𐙘𐙝𐙢𐙧𐙬𐙱𐙶𐙻𐚀𐚅𐚊𐚏𐚔𐚙𐚞𐚣𐚨𐚭𐚲𐚷𐚼𐛁𐛆𐛋𐛐𐛕𐛚𐛟𐛤𐛩𐛮𐛳𐛸
𐛽𐜂𐜇𐜌𐜑𐜖𐜛𐜠𐜥𐜪𐜯𐜴𐝃𐝈𐝍𐝒𐝡𐝦𐠁𐠋𐠐𐠕𐠚𐠟𐠤𐠩𐠮𐠳𐠸𐡂
𐡇𐡌𐡑𐡛𐡠𐡥𐡪𐡯𐡴𐡹𐡾𐢃𐢈𐢍𐢒𐢗𐢜𐢫𐣢𐣧𐣬𐣱𐣻𐤀𐤅𐤊𐤏𐤔𐤙𐤣𐤨𐤭𐤲𐤷𐦂𐦇𐦌
𐦑𐦖𐦛𐦠𐦥𐦪𐦯𐦴𐦾𐧃𐧈𐧍𐧒𐧗𐧜𐧡𐧦𐧫𐧰𐧵𐧺𐧿𐨎𐨓𐨝𐨢𐨧𐨬𐨱𐩀𐩅𐩔𐩣𐩨𐩭𐩲𐩷𐩼𐪁𐪆𐪋𐪐𐪕𐪚𐪟𐫂𐫇𐫌𐫑𐫖
𐫛𐫠𐫥𐫯𐫴𐬃𐬈𐬍𐬒𐬗𐬜𐬡𐬦𐬫𐬰𐬵𐬺𐬿𐭄𐭉𐭎𐭓𐭘𐭝𐭢𐭧𐭬𐭱𐭻𐮀𐮅𐮊𐮏𐮙𐮭𐰂𐰇𐰌𐰑𐰖𐰛𐰠
𐰥𐰪𐰯𐰴𐰹𐰾𐱃𐱈𐲄𐲉𐲎𐲓𐲘𐲝𐲢𐲧𐲬𐲱𐳀𐳅𐳊𐳏𐳔𐳙𐳞𐳣𐳨𐳭𐳲𐳼𐴁𐴆𐴋𐴐𐴕𐴚𐴟𐴤𐴳𐴸
𒀂𒀇𒀌𒀑𒀖𒀛𒀠𒀥𒀪𒀯𒀴𒀹𒀾𒁃𒁈𒁍𒁒𒁗𒁜𒁡𒁦𒁫𒁰𒁵𒁺𒁿𒂄𒂉𒂎𒂓𒂘𒂝𒂢𒂧𒂬𒂱𒂶𒂻𒃀
𒃅𒃊𒃏𒃔𒃙𒃞𒃣𒃨𒃭𒃲𒃷𒃼𒄁𒄆𒄋𒄐𒄕𒄚𒄟𒄤𒄩𒄮𒄳𒄸𒄽𒅂𒅇𒅌𒅑𒅖𒅛𒅠𒅥𒅪𒅯𒅴𒅹𒅾𒆃𒆈𒆍𒆒𒆗𒆜𒆡𒆦𒆫𒆰𒆵𒆺𒆿𒇄𒇉𒇎𒇓𒇘𒇝𒇢𒇧𒇬𒇱𒇶𒇻𒈀𒈅𒈊
𒈏𒈔𒈙𒈞𒈣𒈨𒈭𒈲𒈷𒈼𒉁𒉆𒉋𒉐𒉕𒉚𒉟𒉤𒉩𒉮𒉳𒉸𒉽𒊂𒊇𒊌𒊑𒊖𒊛𒊠𒊥𒊪𒊯𒊴𒊹𒊾𒋃𒋈𒋍𒋒𒋗𒋜𒋡𒋦𒋫𒋰𒋵𒋺𒋿𒌄𒌉𒌎𒌓𒌘𒌝𒌢𒌧𒌬𒌱𒌶𒌻𒍀𒍅𒍊𒍏𒍔
𒍙𒍞𒍣𒍨𒍭𒍲𒍷𒍼𒎁𒎆𒎋𒎐𒎕𒐃𒐈𒐍𒐒𒐗𒐜𒐡𒐦𒐫𒐰𒐵𒐺𒐿𒑄𒑉𒑎𒑓𒑘𒑝𒑢𒑧𒑬𒑱𒒀𒒅𒒊𒒏𒒔𒒙𒒞
𒒣𒒨𒒭𒒲𒒷𒒼𒓁𒓆𒓋𒓐𒓕𒓚𒓟𒓤𒓩𒓮𒓳𒓸𒓽𒔂𒔇𒔌𒔑𒔖𒔛𒔠𒔥𒔪𒔯𒔴𒔹𒔾𒕃
𓀁𓀆𓀋𓀐𓀕𓀚𓀟𓀤𓀩𓀮𓀳𓀸
𓀽𓁂𓁇𓁌𓁑𓁖𓁛𓁠𓁥𓁪𓁯𓁴𓁹𓁾𓂃𓂈𓂍𓂒𓂗𓂜𓂡𓂦𓂫𓂰𓂵𓂺𓂿𓃄𓃉𓃎𓃓𓃘𓃝𓃢𓃧𓃬𓃱𓃶𓃻𓄀𓄅𓄊𓄏𓄔𓄙𓄞𓄣𓄨𓄭𓄲𓄷𓄼𓅁𓅆𓅋𓅐𓅕𓅚𓅟𓅤𓅩𓅮𓅳𓅸𓅽𓆂
𓆇𓆌𓆑𓆖𓆛𓆠𓆥𓆪𓆯𓆴𓆹𓆾𓇃𓇈𓇍𓇒𓇗𓇜𓇡𓇦𓇫𓇰𓇵𓇺𓇿𓈄𓈉𓈎𓈓𓈘𓈝𓈢𓈧𓈬𓈱𓈶𓈻𓉀𓉅𓉊𓉏𓉔𓉙𓉞𓉣𓉨𓉭𓉲𓉷𓉼𓊁𓊆𓊋𓊐𓊕𓊚𓊟𓊤𓊩𓊮𓊳𓊸𓊽𓋂𓋇𓋌
𓋑𓋖𓋛𓋠𓋥𓋪𓋯𓋴𓋹𓋾𓌃𓌈𓌍𓌒𓌗𓌜𓌡𓌦𓌫𓌰𓌵𓌺𓌿𓍄𓍉𓍎𓍓𓍘𓍝𓍢𓍧𓍬𓍱𓍶𓍻𓎀𓎅𓎊𓎏𓎔𓎙𓎞𓎣𓎨𓎭𓎲𓎷𓎼𓏁𓏆𓏋𓏐𓏕𓏚𓏟𓏤𓏩𓏮𓏳𓏸𓏽𓐂𓐇𓐌𓐑𓐖
𓐛𓐠𓐥𓐪
𔐁𔐆𔐋𔐐𔐕𔐚𔐟𔐤𔐩𔐮𔐳𔐸𔐽𔑂𔑇𔑌𔑑𔑖𔑛𔑠𔑥𔑪𔑯𔑴𔑹𔑾𔒃𔒈𔒍𔒒𔒗𔒜𔒡𔒦𔒫𔒰𔒵𔒺𔒿𔓄𔓉𔓎𔓓𔓘
𔓝𔓢𔓧𔓬𔓱𔓶𔓻𔔀𔔅𔔊𔔏𔔔𔔙𔔞𔔣𔔨𔔭𔔲𔔷𔔼𔕁𔕆𔕋𔕐𔕕𔕚𔕟𔕤𔕩𔕮𔕳𔕸𔕽𔖂𔖇𔖌𔖑𔖖𔖛𔖠𔖥𔖪𔖯𔖴𔖹𔖾𔗃𔗈𔗍𔗒𔗗𔗜𔗡𔗦𔗫𔗰𔗵𔗺𔗿𔘄𔘉𔘎𔘓𔘘𔘝𔘢
𔘧𔘬𔘱𔘶𔘻𔙀𔙅
𖠀𖠅𖠊𖠏𖠔𖠙𖠞𖠣𖠨𖠭𖠲𖠷𖠼𖡁𖡆𖡋𖡐𖡕𖡚𖡟𖡤𖡩𖡮𖡳𖡸𖡽𖢂𖢇𖢌𖢑𖢖𖢛𖢠𖢥𖢪𖢯𖢴𖢹𖢾𖣃𖣈𖣍𖣒𖣗𖣜𖣡𖣦𖣫𖣰
𖣵𖣺𖣿𖤄𖤉𖤎𖤓𖤘𖤝𖤢𖤧𖤬𖤱𖤶𖤻𖥀𖥅𖥊𖥏𖥔𖥙𖥞𖥣𖥨𖥭𖥲𖥷𖥼𖦁𖦆𖦋𖦐𖦕𖦚𖦟𖦤𖦩𖦮𖦳𖦸𖦽𖧂𖧇𖧌𖧑𖧖𖧛𖧠𖧥𖧪𖧯𖧴𖧹𖧾𖨃𖨈𖨍𖨒𖨗𖨜𖨡𖨦𖨫𖨰𖨵
𖩄𖩉𖩎𖩓𖩘𖩝𖩢𖩧𖫐𖫕𖫚𖫟𖫤𖫩𖫳𖬂𖬇𖬌𖬑𖬖𖬛𖬠𖬥𖬪𖬯𖬴𖬹𖬾𖭃𖭒𖭗𖭜𖭡𖭦𖭫𖭰𖭵𖭿𖮄
𖮉𖮎
𖹀𖹅𖹊𖹏𖹔𖹙𖹞𖹣𖹨𖹭𖹲𖹷𖹼𖺁𖺆𖺋𖺐𖺕𖺚𖼃𖼈𖼍𖼒𖼗𖼜𖼡𖼦𖼫𖼰𖼵𖼺𖼿𖽄
𛰁𛰆𛰋𛰐𛰕𛰚𛰟𛰤𛰩𛰮𛰳𛰸𛰽𛱂𛱇𛱌𛱑𛱖𛱛𛱠𛱥𛱪𛱴𛱹𛲃𛲈𛲒𛲗𛲜
𝀁𝀆𝀋𝀐
𝀕𝀚𝀟𝀤𝀩𝀮𝀳𝀸𝀽𝁂𝁇𝁌𝁑𝁖𝁛𝁠𝁥𝁪𝁯𝁴𝁹𝁾𝂃𝂈𝂍𝂒𝂗𝂜𝂡𝂦𝂫𝂰𝂵𝂺𝂿𝃄𝃉𝃎𝃓𝃘𝃝𝃢𝃧𝃬𝃱𝄀𝄅𝄊𝄏𝄔𝄙𝄞𝄣𝄭𝄲𝄷𝄼𝅁𝅆𝅋𝅐𝅕𝅚
𝅘𝅥𝅘𝅩𝅥𝅲𝅮𝅽𝆂𝆇𝆌𝆑𝆖𝆛𝆠𝆥𝆪𝆯𝆴𝆹𝆺𝅥𝅮𝇃𝇈𝇍𝇒𝇗𝇜𝇡𝇦𝈄𝈉𝈎𝈓𝈘𝈝𝈢𝈧𝈬𝈱𝈶𝈻𝉀𝉅
𝋠𝋥𝋪𝋯𝌃𝌈𝌍𝌒𝌗𝌜𝌡𝌦𝌫𝌰𝌵𝌺𝌿𝍄𝍉𝍎𝍓𝍢𝍧𝍬𝍱𝍶
𝐂𝐇𝐌𝐑𝐖𝐛𝐠𝐥𝐪𝐯𝐴𝐹𝐾𝑃𝑈𝑍𝑒𝑗𝑜𝑡𝑦𝑫𝑰𝑵𝑺𝑿𝒄𝒉𝒎𝒓𝒘𝒢𝒬𝒱𝒶𝒻𝓀𝓅𝓊𝓏𝓔𝓙𝓞𝓣𝓨𝓭𝓲𝓷𝓼𝔁𝔐𝔚𝔟𝔤𝔩𝔮𝔳𝔸
𝔽𝕂𝕌𝕖𝕛𝕠𝕥𝕪𝕯𝕴𝕹𝕾𝖃𝖈𝖍𝖒𝖗𝖜𝖡𝖦𝖫𝖰𝖵𝖺𝖿𝗄𝗉𝗎𝗓𝗘𝗝𝗢𝗧𝗬𝗱𝗶𝗻𝘀𝘅𝘊𝘏𝘔𝘙𝘞𝘣𝘨𝘭𝘲𝘷𝘼𝙁𝙆𝙋𝙐𝙕𝙚𝙟𝙤𝙩𝙮𝙳𝙸𝙽𝚂
𝚇𝚌𝚑𝚖𝚛𝚠𝚥𝚪𝚯𝚴𝚹𝚾𝛃𝛈𝛍𝛒𝛗𝛜𝛡𝛦𝛫𝛰𝛵𝛺𝛿𝜄𝜉𝜎𝜓𝜘𝜝𝜢𝜧𝜬𝜱𝜶𝜻𝝀𝝅𝝊𝝏𝝔𝝙𝝞𝝣𝝨𝝭𝝲𝝷𝝼𝞁𝞆𝞋𝞐𝞕𝞚𝞟𝞤𝞩𝞮𝞳𝞸𝞽𝟂𝟇
𝟑𝟖𝟛𝟠𝟥𝟪𝟯𝟴𝟹𝟾
𞸁𞸆𞸋𞸐𞸕𞸚𞸟𞸤𞸩𞸮𞹂𞹇𞹑𞹛𞹪𞹯𞹴𞹹𞹾𞺃𞺈𞺍𞺒𞺗𞺡𞺦𞺫𞺰𞺵𞺺𞻱
🀄🀉🀎🀓🀘🀝🀢🀧🀱🀶🀻🁀🁅🁊
🁏🁔🁙🁞🁣🁨🁭🁲🁷🁼🂁🂆🂋🂐🂤🂩🂮🂳🂸🂽🃂🃇🃌🃑🃖🃛🃠🃥🃪🃯🃴🄃🄈🄍🄒🄗🄜🄡🄦🄫🄰🄵🄺🄿🅄🅉🅎🅓🅘🅝🅢🅧🅬🅱🅶🅻🆀🆅🆊🆏🆔
🆙🆞🆣🆨🆭🇩🇮🇳🇸🇽🈂
🌁🌆🌋🌐🌕🌚🌟🌤🌩🌮🌳🌸🌽🍂🍇🍌🍑🍖🍛🍠🍥🍪🍯🍴🍹🍾🎃🎈🎍🎒🎗🎜🎡🎦🎫🎰🎵🎺🎿🏄🏉🏎🏓🏘🏝🏢🏧🏬🏱🏶🏻🐀🐅🐊🐏🐔🐙🐞🐣🐨
🐭🐲🐷🐼👁👆👋👐👕👚👟👤👩👮👳👸👽💂💇💌💑💖💛💠💥💪💯💴💹💾📃📈📍📒📗📜📡📦📫📰📵📺📿🔄🔉🔎🔓🔘🔝🔢🔧🔬🔱🔶🔻🕀🕅🕊🕏🕔🕙🕞🕣🕨🕭🕲
🕷🕼🖁🖆🖋🖐🖕🖚🖟🖤🖩🖮🖳🖸🖽🗂🗇🗌🗑🗖🗛🗠🗥🗪🗯🗴🗹🗾😃😈😍😒😗😜😡😦😫😰😵😺😿🙄🙉🙎🙓🙘🙝🙢🙧🙬🙱🙶🙻🚀🚅🚊🚏🚔🚙🚞🚣🚨🚭🚲🚷🚼
🛁🛆🛋🛐🛕🛤🛩🛳🛸🜂🜇🜌🜑🜖🜛🜠🜥🜪🜯🜴🜹🜾🝃🝈🝍🝒🝗🝜🝡🝦🝫🝰🞄🞉🞎🞓🞘🞝🞢🞧🞬🞱🞶🞻🟀🟅🟊🟏🟔🟣🟨🠁🠆
🠋🠐🠕🠚🠟🠤🠩🠮🠳🠸🠽🡂🡇🡑🡖🡠🡥🡪🡯🡴🡹🡾🢃🢒🢗🢜🢡🢦🢫🢰🤀🤅🤊🤏🤔🤙🤞🤣🤨🤭🤲🤷🤼🥁🥆🥋🥐
🥕🥚🥟🥤🥩🥮🥳🥸🥽🦂🦇🦌🦑🦖🦛🦠🦥🦪🦯🦴🦹🦾🧃🧈🧍🧒🧗🧜🧡🧦🧫🧰🧵🧺🧿🩲🪁🪆🪐🪕🪚
🪟🪤🪳🫂🫑🫖
Вот результат
range(150000)
,
str.isprintable()==True
удалите все пустые строки (то есть здесь гораздо лучшая версия, полный Unicode):
#!/usr/bin/env/python3.10
import io
with io.open("all_utf-8.txt", "w", encoding="utf8") as f:
for n in range(150000):
try:
i = chr(n)
if i.isprintable():
print(f"{i}", end="", file=f)
if n % 200 == 0:
print(file=f)
except UnicodeError:
pass
Несмотря на то, что 1,114,111 (0x10FFFF в базе 16) является истинным размером возможных «символов» (или глифов) Unicode для печати, я останавливаюсь на 150K, потому что afaik почти все, что после этого, в настоящее время еще не используется (т.е. пусто).