API функция
IsTextUnicode
существовала со времён NT 3.5, если верить истории в Platform SDK. Согласно PSDK, её цель такова:
ФункцияЗатем документация описывает различные тесты, которые может делать функция, когда вы указываете соответствующий флаг:IsTextUnicode
определяет, возможно ли, что буфер содержит какую-то форму Unicode текста. Функция использует различные статистические и детерминированные методы для вынесения своего решения, что также контролируется указываемыми флагами. Когда функция возвращает управление, результаты тестов сообщаются через параметрlpi
.
Вроде звучит впечатляюще и интересно, не так ли?IS_TEXT_UNICODE_ASCII16
Текст Unicode и содержит только ASCII символы (расширенные нулём).IS_TEXT_UNICODE_REVERSE_ASCII16
То же, что и предыдущий, но только с обратным порядком байт.IS_TEXT_UNICODE_STATISTICS
Текст, вероятно, является Unicode, что определено статистическим анализом. Абсолютная уверенность не гарантируется.IS_TEXT_UNICODE_REVERSE_STATISTICS
То же, что и предыдущий, но только с обратным порядком байт.IS_TEXT_UNICODE_CONTROLS
Текст содержит Unicode представления одного или более из следующих непечатных символов: RETURN, LINEFEED, SPACE, CJK_SPACE, TAB.IS_TEXT_UNICODE_REVERSE_CONTROLS
То же, что и предыдущий, но только с обратным порядком байт.IS_TEXT_UNICODE_BUFFER_TOO_SMALL
В тексте слишком мало символов для анализа (менее двух байт).IS_TEXT_UNICODE_SIGNATURE
Текст содержит отметку byte-order (BOM) Unicode ($FEFF).IS_TEXT_UNICODE_REVERSE_SIGNATURE
Текст содержит отметку byte-order (BOM) Unicode с обратным порядком байт ($FFFE).IS_TEXT_UNICODE_ILLEGAL_CHARS
Текст содержит один из следующих недопустимых в Unicode символов: встроенный Reverse BOM, UNICODE_NUL, CRLF (упакованный в один WORD) или $FFFF.IS_TEXT_UNICODE_ODD_LENGTH
Число символом в строке нечётно. Строка с нечётной байтовой длиной не может быть Unicode строкой по определению.IS_TEXT_UNICODE_NULL_BYTES
Текст содержит нулевые байты, что указывает на не-ASCII текст.IS_TEXT_UNICODE_UNICODE_MASK
Этот флаг является комбинациейIS_TEXT_UNICODE_ASCII16
,IS_TEXT_UNICODE_STATISTICS
,IS_TEXT_UNICODE_CONTROLS
иIS_TEXT_UNICODE_SIGNATURE
.IS_TEXT_UNICODE_REVERSE_MASK
Этот флаг является комбинациейIS_TEXT_UNICODE_REVERSE_ASCII16
,IS_TEXT_UNICODE_REVERSE_STATISTICS
,IS_TEXT_UNICODE_REVERSE_CONTROLS
иIS_TEXT_UNICODE_REVERSE_SIGNATURE
.IS_TEXT_UNICODE_NOT_UNICODE_MASK
Этот флаг является комбинациейIS_TEXT_UNICODE_ILLEGAL_CHARS
,IS_TEXT_UNICODE_ODD_LENGTH
и ещё двух не используемых сегодня битовых полей.IS_TEXT_UNICODE_NOT_ASCII_MASK
Этот флаг является комбинациейIS_TEXT_UNICODE_NULL_BYTES
и трёх не используемых сегодня битовых полей.
Тривиальный факт: код для флага, который когда-то был документирован (
IS_TEXT_UNICODE_DBCS_LEADBYTE
), всё ещё сидит в функции (и флаг всё ещё объявлен в заголовочнике - PSDK никогда так грубо не ломает код других людей). Но этот флаг работает откровенно ужасно - видимо, поэтому он и больше не документируется. Я настоятельно рекомендую его не использовать. И игнорировать его, когда вам его возвращают. Флаг не опасен - ничего такого, просто он не является ужасно полезным для своей цели (определения, что текст является DBCS).Как я упоминал, эта функция была с нами со времён NT 3.5. Она была написана кем-то вне команды NLS (как она была в те дни). Это довольно впечатляюще, поскольку в те дни не было такой осведомлённости о Unicode, как сегодня...
В те горячие дни, когда для большинства разработчиков Unicode был немногим большим, чем иностранное слово, воспринимаемое как "удвоение памяти и пространства, необходимых для строк", эта функция в основном использовалась как способ узнать, когда вызывать
WideCharToMultiByte
, когда преобразовывать строки из Unicode1, и даже для такой цели было не так уж много вызывающих. В NT 4.0 эта функция не получила значительно большего использования, хотя Windows 2000 число вызывающих её во всём дереве исходных кодов Windows увеличилось примерно в три раза (до 65-ти или около того). Не так много изменений было с вызывающей стороны и в XP или Server 2003. Я не особо против этого факта.В какое-то время между XP и Server 2003, я добавил её в MSLU, как хороший жест для разработчиков, которые были разочарованы тем, что она имеется только в NT API2.
Тем не менее, как указывает название этого поста, я не люблю IsTextUnicode.
Вы можете подумать, почему бы это - давайте, я даю вам три попытки.
Попытка №1: потому что я ею не владею?
Извините, это не так - но ваше мнение о моём эго взято на заметку :-)
Я дам вам подсказку.
Подсказка №1: посмотрите на описание в Platform SDK (я добавлю выделение, чтобы усилить подсказку):
ФункцияIsTextUnicode
определяет, возможно ли, что буфер содержит какую-то форму Unicode текста. Функция использует различные статистические и детерминированные методы для вынесения своего решения, что также контролируется указываемыми флагами. Когда функция возвращает управаление, результаты тестов сообщаются через параметрlpi
.
Попытка №2: Извини, я имел ввиду, потому что функция не принадлежит команде NLS?
Хмм, извините. Я понял, что вы имели ввиду ещё в первой попытке.
Я дам ещё одну подсказку.
Подсказка №2: У этой функции за всё время было только одно значительное изменение - к параметру
lpBuffer
был добавлен модификатор const
.Теперь дошло? Подумайте внимательно, это ваша последняя попытка.
Попытка №3: Потому что она рассматривает "CRLF (упакованные в одно WORD)" как недопустимый символ, даже хотя U+0D0A - это MALAYALAM LETTER UU?
Ооо, отлично - это выглядит как баг флага
IS_TEXT_UNICODE_ILLEGAL_CHARS
. Что ещё круче - вы даже разобрались с порядком байт. Или, может быть, вы просто не заметили этого, поскольку и ASCII CRLF, упакованные в одно WORD, и этот символ будут перевёрнуты на little-endian системах, так что они будут выглядеть как $0A0D
в памяти, а если вы не разрешаете проверки на обратный порядок байт, то вы всё равно оказываетесь правы.С учётом того, что поддержка Malayalam, описанная в предыдущем посте, это довольно неудобная ситуация. Или, может быть, с учётом факта, что эта кодовая точка была добавлена в Unicode 1.1 (согласно DerivedAge.txt), который был выпущен в Июне 1993-го (согласно enumeratedversions.html), это будет в особенности стыдно. Хотя это делает этот комментарий особенно изумительным:
// Следующее не является пока Unicode символом, // но он ожидается при чтении в ASCII файлах, // которые используют CRLF на little endian машине.Если вы подумаете об этом, то большинство UTF-16 big endian файлов должно придти от какой-то другой системы - которая, вероятно, использует просто CR или LF в качестве разделителя строк, даже если это просто ASCII. Я думаю, теперь понятно, почему нет аналогичной проверки для этой "недопустимой" комбинации для обратного порядка байт (big-endian)? :-) Что делает всю проверку
IS_TEXT_UNICODE_ILLEGAL_CHARS
весьма странной, если не полностью бесполезной.Для фанатов MSLU: да, я портировал этот баг, хотя и не целенаправленно. Извините, я не привык читать кодовые точки как реверсированные байты...
Конечно же, поскольку я не знал об этой проблеме раньше, она не может быть причиной, почему я не люблю эту функцию. Чёрт, да если бы не этот придуманный разговор, я бы так и не узнал про неё. К счастью для всех, я проявил эту психологическую дисфункцию на глазах у всех и поэтому не могу ещё больше быть смущённым, сообщая по ней баг, верно?
Так как вы нашли баг десятилетней давности: ладно, это все еще попытка №3 :-)
Ещё одна подсказка:
Подсказка №3: В нижележащих мезанизмах этой функции не было изменений как минимум со времён NT 3.51 (а, вероятно, и со времён изначального релиза в NT 3.5).
Ещё варианты будут?
Попытка №4: Потому что, кажется, она тестирует только первые 256 байтов, вне зависимости от того, насколько большой текст я передаю?
Ну, вообще-то нет. Меня это никогда не волновало, даже когда я ещё не работал в Microsoft. Я никогда не встречался со случаем, когда это на что-то влияло. Было бы неплохо, если бы кто-то изменил это поведение, но я не потеряю свой сон из-за этого - определённо это не та причина, почему я не люблю функцию!
Ладно, я просто вам скажу. Потому что функция должна проверять, следует ли строка стандарту. Почему следующие флаги так и не были добавлены за все эти годы, или даже в начальном релизе?
IS_TEXT_UNICODE_UNPAIRED_SURROGATES
Поскольку ситуация, когда старший (high) суррогат появляется без младшего (low), который идёт за ним, является недопустимой, то почему бы не обнаруживать такие случаи?IS_TEXT_REVERSE_UNICODE_ILLEGAL_CHARS
Кажется, отсутсвие этого флага является нечестным для UTF-16BE, не так ли?IS_TEXT_UNICODE_INVALID_FOR_4_00
Очевидно, такие новые флаги могли быть добавлены для каждой значительной версии - что может быть проще для проверки того, что недопустимо, в каждом официальном списке?IS_TEXT_UNICODE_INVALID_SCRIPT_USAGE
Существует множество типов последовательностей байт, которые могут указать на недопустимое использование, начиная от комбинирующих отметок из одного языка, используемых для символов другого языка, заканчивая недопустимыми последовательностями с неверным порядком канонического комбинирования классов, и так далее.IS_TEXT_UNICODE_VALID_UTF8_PER_RFC2799
Первоначальное описание UTF-8 в RFC 279, которое, я думаю, используется Блокнотом3.IS_TEXT_UNICODE_VALID_UTF8_PER_UNICODE
Более строгое определение UTF-8, которое не допускает суррогатные последовательности и другие не кратчайшие формы.IS_TEXT_UNICODE_VALID_UTF32
/IS_TEXT_UNICODE_VALID_REVERSE_UTF32
Эти флаги могут быть скомбинированы с некоторыми из старых флагов определения, если найдена сигнатура UTF-32 LE или BE.IS_TEXT_UNICODE_UCS2_32
/IS_TEXT_UNICODE_REVERSE_UCS2_32
Аналог флаговIS_TEXT_UNICODE_ASCII16
/IS_TEXT_UNICODE_REVERSE_ASCII16
, они укажут на UTF-32, который выглядит так, что он может быть представлен как UTF-16 без суррогатных пар.
Вы уловили идею: Unicode - это динамичный стандарт, становящийся со времением всё более интересным и сложным, не только сам по себе, но и в том, как он используется платформой. Как может API функция, написанная больше десятилетия назад и никогда не обновляемая, чьей работой является выяснение "в этом буфере лежит Unicode текст?", даже хотя бы надеяться догнать такой стандарт?
1 - Блокнот является достойным упоминания исключением из этого правила, поскольку он использует функцию только для файлов без BOM.
2 - Аналогично тому, как были добавлены
BeginUpdateResource
, UpdateResource
и EndUpdateResource
, хотя я должен признать, что функции *UpdateResource появились потому, что Matt Curland сделал всю работу, чтобы заставить эти функции работать в Win9x :-)3 - Это правила, которые используются
MultiByteToWideChar
в последние годы. Ирония в том, что функция MultiByteToWideChar
используется Блокнотом для конвертации файлов, которые были определены как UTF-8 по правилам RFC 2279, что означает, что любые недопустимые последовательности будут молчаливо проигнорированы даже без предупреждения. Лучше держите эти файлы в CESU-8 подальше от последних версий Блокнота!This post sponsored by out much maligned little brother "ഊ" (U+0d0a, a.k.a. MALAYALAM LETTER UU)
Кто, как и остальные символы из алфавита Malayalam script, чувствует себя хорошо поддерживаемым XP SP 2, но только затем, чтобы обнаружить, что функция
IsTextUnicode
не разделяет это мнение...
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.