Интересно, почему большинство современных решений, построенных с использованием 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.
Ответы:
℞ ℞ : 𝟕 𝘿𝙞𝙨𝙘𝙧𝙚𝙩𝙚 𝙍𝙚𝙘𝙤𝙢𝙢𝙚𝙣𝙙𝙖𝙩𝙞𝙤𝙣𝙨
Установите ваш
PERL_UNICODE
envariable вAS
. Это делает все сценарии Perl декодируемыми@ARGV
как строки UTF ‑ 8 и устанавливает кодировку всех трех параметров stdin, stdout и stderr в UTF ‑ 8. И то, и другое - глобальные, а не лексические последствия.В верхней части исходного файла (программа, модуль, библиотека,
do
hickey) явно утверждают, что вы используете Perl версии 5.12 или выше, используя:Включите предупреждения, поскольку предыдущее объявление включает только ограничения и функции, а не предупреждения. Я также предлагаю превратить предупреждения Unicode в исключения, поэтому используйте обе эти строки, а не одну из них. Однако обратите внимание , что при v5.14, то
utf8
класс предупреждения включает в себя три других subwarnings , которые все могут быть отдельно включены:nonchar
,surrogate
, иnon_unicode
. Этим вы, возможно, захотите осуществлять больший контроль.Объявите, что этот источник кодируется как UTF ‑ 8. Хотя когда-то давно эта прагма делала другие вещи, теперь она служит одной единственной цели, а не другим:
Объявите, что все, что открывает файловый дескриптор в этой лексической области, но не где-либо еще, означает, что этот поток закодирован в UTF-8, если вы не укажете иначе. Таким образом, вы не влияете на код другого модуля или другой программы.
Включить именованные символы через
\N{CHARNAME}
.Если у вас есть
DATA
дескриптор, вы должны явно установить его кодировку. Если вы хотите, чтобы это был UTF ‑ 8, то скажите:Конечно, нет конца другим вопросам, которые могут в конечном итоге вас заинтересовать, но их будет достаточно, чтобы приблизиться к государственной цели «заставить все просто работать с UTF-8», хотя и для несколько ослабленного смысла этих терминов.
Еще одна прагма, хотя она не связана с Unicode, это:
Настоятельно рекомендуется.
🌴 🐪🐫🐪 🌞 𝕲𝖔 𝕿𝖍𝖔𝖚 𝖆𝖓𝖉 𝕯𝖔 𝕷𝖎𝖐𝖊𝖜𝖎𝖘𝖊 🌞 🐪🐫🐪 🐁
🎁 🐪 𝕭𝖔𝖎𝖑𝖊𝖗⸗𝖕𝖑𝖆𝖙𝖊 𝖋𝖔𝖗 𝖀𝖓𝖎𝖈𝖔𝖉𝖊⸗𝕬𝖜𝖆𝖗𝖊 𝕮𝖔𝖉𝖊 🐪 🎁
Мой собственный шаблон в эти дни имеет тенденцию выглядеть следующим образом:
🎅 𝕹 𝖔 𝕸 𝖆 𝖌 𝖎 𝖈 𝕭 𝖚 𝖑 𝖑 𝖊 𝖙 🎅
Сказать, что «Perl должен [ как-то! ] включить Unicode по умолчанию »даже не задумывалась о том, чтобы обойтись, говоря достаточно для того, чтобы быть хоть немного полезной в каком-то редком и изолированном случае. Юникод - это намного больше, чем просто большой репертуар персонажей; Кроме того, все эти персонажи взаимодействуют по-разному.
Даже простейшие минимальные меры, которые (некоторые) люди думают, что они хотят, гарантированно сокрушат миллионы строк кода, кода, который не имеет шансов «обновить» до вашего изящного нового модного мира Brave New World .
Это намного сложнее, чем люди притворяются. Я много думал об этом за последние несколько лет. Я хотел бы, чтобы мне показали, что я не прав. Но я так не думаю. Юникод существенно сложнее, чем модель, которую вы хотели бы навязать ему, и здесь есть сложность, которую вы никогда не сможете заметить. Если вы попытаетесь, вы сломаете либо свой собственный, либо чужой код. В какой-то момент вы просто должны сломаться и узнать, что такое Unicode. Вы не можете притворяться, что это то, чем это не является.
🐪 делает все возможное, чтобы упростить Unicode, гораздо больше, чем все, что я когда-либо использовал. Если вы думаете, что это плохо, попробуйте что-нибудь другое на некоторое время. Затем вернитесь к 🐪: либо вы вернетесь в лучший мир, либо вы принесете то же самое с собой, чтобы мы могли использовать ваши новые знания, чтобы улучшить these в этих вещах.
💡 𝕴𝖉𝖊𝖆𝖘 𝖋𝖔𝖗 𝖆 𝖀𝖓𝖎𝖈𝖔𝖉𝖊 ⸗ 𝕬𝖜𝖆𝖗𝖊 🐪 𝕷𝖆𝖚𝖓𝖉𝖗𝖞 𝕷𝖎𝖘𝖙 💡
Как минимум, вот некоторые вещи, которые могут потребоваться для того, чтобы enable «включить Юникод по умолчанию», как вы выразились:
Все 🐪 исходный код должен быть в 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
d:encoding(UTF-8)
, а не только:utf8
.Кодовые точки между 128–255 следует понимать как the как соответствующие кодовые точки 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. Там нет I / O слоя для них еще , что я знаю, но вижу НКА , NFD , nfkd и NFKC .Сравнение строк в 🐪 используя
eq
,ne
,lc
,cmp
,sort
, и с & куб.см всегда неправы. Так что вместо@a = sort @b
, вам нужно@a = Unicode::Collate->new->sort(@b)
. Можно также добавить это к вашемуexport PERL5OPTS=-MUnicode::Collate
. Вы можете кэшировать ключ для бинарных сравнений.🐪 встроенные модули любят
printf
иwrite
делают неправильные вещи с данными Unicode. Вы должны использовать вUnicode::GCString
модуль для первого, и как то, что и также модуль , а для последнего. Смотрите UWC и Unifmt .Unicode::LineBreak
Если вы хотите, чтобы посчитать как целые числа, то вы будете иметь , чтобы запустить свои
\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
методы тоже. Они имеют явные преимущества по сравнению со встроенными модулями.Иногда этого все еще недостаточно, и вместо этого вам нужен модуль 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» и «are»,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
ширину 🐪 для дополнения и обоснования данных Юникода, неверен и неверен.Код, который полагает, что как только вы успешно создадите файл с заданным именем, при запуске
ls
илиreaddir
в окружающем каталоге вы обнаружите, что файл с именем, под которым вы его создали, содержит ошибки, сломан и ошибочен. Хватит удивляться этому!Код, который считает UTF-16 кодированием с фиксированной шириной, глуп, сломан и ошибочен. Отзыв их лицензии на программирование.
Код, который обрабатывает кодовые точки из одной плоскости, отличной от кода из любой другой плоскости, фактически является ошибочным и неверным. Идти обратно в школу.
Код, который считает, что подобные вещи
/s/i
могут только совпадать,"S"
либо"s"
ошибаться, либо ошибаться. Вы были бы удивлены.Код, который используется
\PM\pM*
для поиска кластеров графемы вместо использования\X
, поврежден и ошибочен.Людей, которые хотят вернуться в мир ASCII, следует искренне поощрять к этому, и в честь их славного обновления им должна быть предоставлена бесплатная электрическая ручная пишущая машинка для всех их потребностей при вводе данных. Сообщения, отправленные им, следует отправлять по телеграфу по 40 символов в строке и доставлять вручную курьером. СТОП.
😱 𝕾 𝖀 𝕸 𝕸 𝕬 𝕽 𝖄 😱
Я не знаю, сколько вы можете получить «Unicode по умолчанию в 🐪», чем то, что я написал. Ну, да, я делаю: вы должны использовать
Unicode::Collate
иUnicode::LineBreak
тоже. И, вероятно, больше.Как вы видите, есть слишком много Unicode вещей , которые вы действительно действительно должны беспокоиться о для там когда - либо существует такая вещь , как « по умолчанию в Unicode».
То, что вы собираетесь обнаружить, так же, как мы делали это в п. 5.8, что просто невозможно навязать все эти вещи к коду, который не был разработан с самого начала, чтобы объяснить их. Твой благонамеренный эгоизм просто сломал весь мир.
И даже после того, как вы это сделаете, по-прежнему есть критические проблемы, которые требуют большого количества размышлений, чтобы получить право. Там нет переключателя вы можете щелкнуть. Ничего, кроме мозга, а я имею в виду настоящий мозг , здесь не хватит. Есть чертовски много вещей, которые вы должны изучить. По модулю отступления к ручной пишущей машинке вы просто не можете надеяться пробраться в неведении. Это 21 век, и вы не можете желать Unicode умышленным невежеством.
Вы должны изучить это. Период. Никогда не будет так легко, что «все просто работает», потому что это гарантирует, что многие вещи не работают - что лишает законной силы предположение, что когда-либо может быть способ «заставить все это работать».
Возможно, вам удастся получить несколько разумных значений по умолчанию для очень немногих и очень ограниченных операций, но не думая о вещах намного больше, чем я думаю, у вас есть.
Как только один пример, каноническое упорядочение вызовет некоторые реальные головные боли. 😭
"\x{F5}"
«õ» ,"o\x{303}"
«õ» ,"o\x{303}\x{304}"
«ȭ» и"o\x{304}\x{303}"
«ō̃» должны совпадать с «õ» , но как в мире вы это сделаете? Это сложнее, чем кажется, но это то, что вам нужно учитывать. 💣Если есть что-то, что я знаю о Perl, это то, что его биты Unicode делают и не делают, и вот что я вам обещаю: «̲ᴛ̲ʜ̲ᴇ̲ʀ̲ᴇ̲ ̲ɪ̲s̲ ̲ɴ̲ᴏ̲ ̲U̲ɴ̲ɪ̲ᴄ̲ᴏ̲ᴅ̲ᴇ̲ ̲ᴍ̲ᴀ̲ɢ̲ɪ̲ᴄ̲ ̲ʙ̲ᴜ̲ʟ̲ʟ̲ᴇ̲ᴛ̲ ̲» 😞
Вы не можете просто изменить некоторые значения по умолчанию и получить плавный ход. Это правда, что я запускаю 🐪 с
PERL_UNICODE
установленным на"SA"
, но это все, и даже это в основном для командной строки. Для реальной работы я прошёл все многочисленные шаги, описанные выше, и делаю это очень, ** очень ** осторожно.😈 ¡ƨ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 для кодирования.)Если мы перепишем наш однострочник:
Мы набираем 文字 化 け и получаем «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 предполагал, что все было текстовым или двоичным кодом Latin-1. Поэтому, когда данные поступают в вашу программу и вы начинаете обрабатывать их как текст, Perl обрабатывает каждый октет как символ Latin-1. Вот почему, когда мы спросили длину «文字 化 け», мы получили 12. Perl предположил, что мы работаем со строкой Latin-1 «åååã» (которая состоит из 12 символов, некоторые из которых не печатаются).
Это называется «неявным обновлением», и это вполне разумно, но это не то, что вам нужно, если ваш текст не Latin-1. Вот почему так важно явно декодировать ввод: если вы этого не сделаете, Perl сделает это, и он может сделать это неправильно.
Люди сталкиваются с проблемами, когда половина их данных является правильной символьной строкой, а некоторые все еще двоичными. Perl интерпретирует двоичную часть, как будто это текст Latin-1, а затем объединяет ее с правильными символьными данными. Это будет выглядеть так, как будто правильное обращение с вашими персонажами нарушило вашу программу, но в действительности вы просто недостаточно исправили это.
Вот пример: у вас есть программа, которая читает текстовый файл в кодировке UTF-8, вы добавляете Unicode
PILE OF POO
к каждой строке и распечатываете ее. Вы пишете это так:А затем запустите некоторые данные в кодировке UTF-8, например:
Он печатает данные UTF-8 с poo в конце каждой строки. Отлично, моя программа работает!
Но нет, вы просто делаете двоичную конкатенацию. Вы читаете октеты из файла, удаляя
\n
помощью chomp, а затем добавляете байты в UTF-8 представлениеPILE OF POO
символа. Когда вы пересмотрите свою программу, чтобы декодировать данные из файла и закодировать вывод, вы заметите, что вместо poo вы получаете мусор («ð ©»). Это заставит вас поверить, что декодирование входного файла - неправильная вещь. Это не.Проблема в том, что poo неявно обновляется как latin-1. если ты
use utf8
сделаете буквальный текст вместо двоичного, то он снова заработает!(Это проблема номер один, которую я вижу, когда помогаю людям с Юникодом. Они правильно расставались, и это нарушало их программу. Вот что печально в отношении неопределенных результатов: у вас может быть рабочая программа в течение длительного времени, но когда вы начинаете ее восстанавливать, это ломает. Не волнуйтесь, если вы добавляете операторы кодирования / декодирования в свою программу, и это ломается, это просто означает, что у вас есть больше работы. В следующий раз, когда вы с самого начала будете проектировать с Unicode, это будет намного легче!)
Это действительно все, что вам нужно знать о Perl и Unicode. Если вы скажете Perl, какие у вас данные, у вас будет лучшая поддержка Unicode среди всех популярных языков программирования. Однако, если вы предполагаете, что он будет волшебным образом знать, какой тип текста вы подаете, то вы безвозвратно уничтожите свои данные. То, что ваша программа работает сегодня на вашем терминале UTF-8, не означает, что она будет работать завтра с файлом в кодировке UTF-16. Так что сделайте это сейчас безопасным и избавьте себя от головной боли, связанной с уничтожением данных ваших пользователей!
Простая часть обработки Unicode - это кодирование вывода и декодирование ввода. Сложная часть - найти все ваши входные и выходные данные и определить, какая это кодировка. Но именно поэтому вы получаете большие деньги :)
источник
Encode
модуля утомительно и подвержено ошибкам, и это делает чтение кода относительно ввода-вывода действительно болезненным. Уровни ввода / вывода обеспечивают решение, поскольку они прозрачно кодируют и декодируют, где это необходимо.open
и учитывайтеbinmode
их спецификацию, а прагмаopen
устанавливает значения по умолчанию, как рекомендует tchrist в своем ответе.Мы все согласны с тем, что это сложная проблема по многим причинам, но именно поэтому мы стараемся облегчить задачу для всех.
В CPAN недавно появился модуль utf8 :: all , который пытается «включить Unicode. Все это».
Как уже указывалось, вы не можете волшебным образом заставить всю систему (внешние программы, внешние веб-запросы и т. Д.) Также использовать Unicode, но мы можем работать вместе, чтобы сделать разумные инструменты, облегчающие решение общих проблем. Вот почему мы программисты.
Если utf8 :: all не делает то, что вы считаете нужным, давайте улучшим его, чтобы сделать его лучше. Или давайте создадим дополнительные инструменты, которые вместе могут максимально удовлетворить различные потребности людей.
`
источник
utf8::all
модуле. Это было написано передunicode_strings
функцией, которая Fɪɴᴀʟʟʏ ᴀɴᴅ ᴀᴛ Lᴏɴɢ Lᴀsᴛ исправляет регулярные выражения, чтобы иметь/u
на них. Я не уверен, что это вызывает исключение при ошибках кодирования, и это то, что вы действительно должны иметь. Он не загружается вuse charnames ":full"
прагму, которая еще не загружена. Он не предупреждает о[a-z]
и таких,printf
струнных ширинах, используя\n
вместо\R
и.
вместо того , чтобы\X
, но , возможно , those're большеPerl::Critic
дела. Если бы это был я, я бы добавил 𝐍𝐅𝐃 в и 𝐍𝐅𝐂 из.unichars -gs '/(?=\P{Ll})\p{Lower}|(?=\P{Lu})\p{Upper}/x' | ucsort --upper | cat -n | less -r
. Точно так же маленькие шаги предварительной обработки, такие как,... | ucsort --upper --preprocess='s/(\d+)/sprintf "%#012d", $1/ge'
могут быть действительно хорошими, и я не хотел бы принимать решения других за них. Я все еще строю свой набор инструментов Unicode .Я думаю, вы неправильно понимаете 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 и как он работает. В противном случае вы не сможете использовать его эффективно.
источник
use utf8_everywhere
люди счастливы. Почему не последний?Читая эту ветку, у меня часто складывается впечатление, что люди используют « 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 из-за проблем с транскодированием).
источник
-C
опции, чтобы убедиться, что Perl находится на той же странице, что и я в Юникоде, потому что я продолжаю предлагать использовать ISO 8859/1 вместо Юникода, даже если я явно настроен$LANG
и$LC_ALL
правильно настроен . (Это может на самом деле отражать ошибки в библиотеках языковых стандартов платформы.) Как бы то ни было, очень досадно, что я не могу использовать iTivo в программах с акцентами в них, потому что скрипты Perl, которые выполняют работу, сбиваются с ошибками преобразования.-C
без вариантов глючит и подвержен ошибкам . Ты разбиваешь мир. УстановитеPERL5OPT
envariable,-C
и вы поймете, что я имею в виду. Мы попробовали этот путь назад в v8.8, и это было катастрофой. Вы просто не можете и не должны сообщать программам, которые этого не ожидают, о том, что теперь они имеют дело с Unicode, нравится им это или нет. Есть также проблемы с безопасностью. По крайней мере, все, что делаетprint while <>
, сломается, если передаются двоичные данные. Так же будет весь код базы данных. Это ужасная идея.-C
без вариантов. Конкретный вызов, с которым я работал, был-CSDA
. Тем не менее, я застрял с 5.8.x в течение долгого времени (привет MacPorts ...), так что, возможно, это было частью этого.Вы должны включить функцию 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, где форма следует за функцией, а реализация сокращена и оптимизирована.
источник