Сегодня я проснулся и почувствовал, что что-то было ужасно неправильно с моим кодом и каждой библиотекой, которую я когда-либо использовал, и я думаю, что я был прав... (или, пожалуйста, укажите, где мои рассуждения ошибочны)
Пусть начнется я десять или два назад во времени, все было хорошо в мире. Я говорил с моим соседом, и он говорил на одном языке: просто английский. Мне, моему соседу и Windows, казалось, что мы сохранили нашу строку в 8-битном char
, потому что все используемые символы могли быть сохранены в доступных 2 ^ 8 = 256 доступных комбинациях.
Тогда появилось чудесное интернет-сообщество и позволило мне поговорить с некоторыми друзьями в Европе (у которых не было времени изучать английский язык). Это затруднилось с нашим форматом char
, количество используемых символов превысило 256, поэтому в нашем совершенно упрощенном видении мы решили использовать 16-битные wchar_t
s. Кое-что называется Unicode UCS-2. Он имеет 2 ^ 16 = 65,536 доступных комбинаций, и этого должно быть достаточно для каждого языка в мире! Убедившись в нашей корректности, мы добавили 16-битные функции Windows API W
, такие как MessageBoxW
и CreateWindowW
. Мы убедили каждого программиста в нашей религии и не поощряли использование злых 8-битных аналогов (MessageBoxA
и CreateWindowA
) и автоматически отображали вызов MessageBox
на MessageBoxW
, определяя _UNICODE
в наших сборках. Поэтому мы должны также использовать функции wcs
вместо старых str
функций (например, strlen
теперь должен быть wcslen
или использовать автоматически отображаемый _tcslen
).
Тогда все стало плохо, оказалось, что в мире есть другие люди, которые использовали даже более странные глифы (без обид), чем наши: японцы, китайцы и т.д. Это плохо, потому что, например, у китайцев более 70 000 разных персонажей. Много ругательств произошло и оставило нам новый тип юникода: UTF-16. Он также использует 16-битный тип данных, но некоторые символы требуют двух 16-битных значений (называемых суррогатной парой). Это означает, что мы не можем использовать индексы для этих 16-битных строк (например, строка [4] может не возвращать 5-й символ). Для исправления Windows API было решено, что все функции W
теперь должны поддерживать формат UTF-16, это было простое решение, так как все старые строки UCS-2 были действительными строками UTF-16. Однако, поскольку мы храбрые программисты, теперь мы используем функции wcs
. К сожалению, эти функции не являются суррогатными и все еще соответствуют формату UCS-2...
Хорошо, вы сделали это через мою длинную рецензию:) Теперь у меня есть несколько вопросов/точек интереса:
-
Хорошо, я доволен использованием UTF-8 для хранения. Когда я читаю файл (с диска или ответа HTTP), я обнаруживаю подпись UTF-8
"\xEF\xBB\xBF"
и помещаю содержимое черезMultiByteToWideChar
, которое оставляет меня с помощью строки UTF-16. Я могу использовать это с функциями APIW
, без проблем. Но теперь я хочу изменить строку, заменить некоторые символы и т.д. Старые добрые функцииwcs
больше не полезны, какие функции основной строки имеют UTF-16? Или есть какая-то великолепная библиотека, которую я не знаю? Изменить: похоже, ICU - довольно хорошее решение. Я также обнаружил, что функцииwcs
не совсем бесполезны, вы можете, например, использоватьwcsstr
для поиска, по существу просто сравниваетwchar_t
s. Единственная проблема - длина строки. -
У вас нет чувства, что уродливая ошибка была сделана, когда мы были вынуждены использовать 16-битные функции с дефицитом
W
. Разве проблема не была распознана на гораздо более ранней стадии, и пусть все исходные функции API берут строки UTF-8 и включают правильные подпрограммы строковой манипуляции? Или это уже возможно, и я ужасно ошибаюсь? Изменить: может быть, это был глупый вопрос, задним числом действительно замечательно, не нужно никому прикладывать кого-либо прямо сейчас;) -
Для быстрого доступа индекса к символам мы должны хранить строки в 32-битных значениях. Это распространено? (Я слышу, как вы думаете: а затем мы сталкиваемся с внеземным языком, требующим больше комбинаций, и забава начинается снова и снова). Кажется, что недостатком этого подхода является то, что мы должны преобразовать строку обратно в UTF-16 каждый раз, когда мы вызываем вызовы Windows API. Изменить: просто, чтобы процитировать Альфа П. Штайнбаха, один символ за индекс - это безнадежный сон, я вижу это сейчас. Одна вещь, которую я полностью пропустил, была diacritics. Я также думаю, что хорошо обрабатывать в собственной кодировке ОС (для Windows UTF-16). Хотя UTF-8 был бы лучшим выбором, мы застряли в UTF-16 сейчас, нет смысла конвертировать назад и вперед между вашим кодом и API. Как предложено ниже, я буду отслеживать части в строке самими указателями вместо количества символов.
Я думаю, что ты заслужил себя прекрасным чаем чая, борющегося за этот длинный вопрос, иди до него, прежде чем ответить;)
Изменить: я согласен с тем, что мой вопрос закрыт, это будет лучше подходит для сообщения в блоге, но опять же я не пишу блог. Я думаю, что эта кодировка символов важна и должна быть следующей темой в любой книге программирования после простого примера приветствия! Публикация здесь привлекает внимание многих экспертов, эти люди не читают какой-либо случайный блог, и я высоко ценю их мнение. Поэтому благодарим всех за вклад.