книги хакеры / журнал хакер / 191_Optimized
.pdf
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|||
|
|
|
C |
|
|
E |
|
|
|
|
|
|
C |
|
E |
|
|
|
||||||
|
|
X |
|
|
|
|
|
|
|
|
|
X |
|
|
|
|
|
|
||||||
|
- |
|
|
|
|
|
|
d |
|
|
- |
|
|
|
|
|
d |
|
||||||
|
F |
|
|
|
|
|
|
|
|
t |
|
|
F |
|
|
|
|
|
|
|
t |
|
||
|
D |
|
|
|
|
|
|
|
|
|
i |
|
|
D |
|
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
|
r |
|
|
|
|
|
|
|
|
|
|
r |
|||
P |
|
|
|
|
|
NOW! |
o |
|
P |
|
|
|
|
|
NOW! |
o |
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
BUY |
|
|
|
|
|
|
|
BUY |
|
|
|||||||||
|
|
|
|
to |
116 m |
Академия С++ |
|
|
|
|
to |
|
|
|
|
|
|
|||||||
w Click |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||||
|
|
ХАКЕР 12 /191/ 2014 |
|
|
|
|
|
|
m |
|||||||||||||||
|
|
|
w Click |
|
|
|
|
|
|
|
||||||||||||||
w |
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
||
|
w |
|
|
|
|
|
|
|
|
|
o |
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
|
g |
.c |
|
|
. |
|
|
|
|
g |
.c |
|
||||||
|
|
p |
|
|
|
|
|
|
|
|
|
|
p |
|
|
|
|
|
|
|
||||
|
|
|
df |
|
|
|
n |
e |
|
|
|
|
df |
|
|
n |
e |
|
||||||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
|
-x cha |
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
Альтернативным решением |
стала однобайтовая |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
кодировка UTF-8, которая мало того, что совместима |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
с ASCII (старший бит, равный нулю, отвечает за одно- |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
байтовые символы), так еще и позволяет кодировать |
UTF (Unicode Transformation Format) — по сути байтовое представление |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
вплоть до 4-байтового целого, то есть свыше 2 мил- |
текста, использующее коды символов из таблицы Юникода, запако- |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
лиардов символов. Плата, правда, довольно суще- |
ванные в байтовый массив согласно стандартизированным правилам. |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
ственная, символы получаются различного размера, |
Наиболее популярны UTF-8 и UTF-16, которые представляют символы |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
и чтобы, например, заменить латинский символ R |
элементами по 8 бит и по 16 бит соответственно. В обоих случаях сим- |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
на русский символ Я, потребуется полностью пере- |
вол совершенно необязательно занимает ровно 8 или 16 бит, например, |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
строить всю строку, что значительно дороже обычной |
в UTF-16 используются суррогатные пары, по сути пары 16-битных зна- |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
замены кода в случае 4-байтового wchar_t. Таким об- |
чений, используемых вместе. В результате значащих битов становится |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
разом, любая активная работа с символами строки |
меньше (20 в случае суррогатной пары), чем битов в группе представ- |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
в UTF-8 может поставить крест на идее использовать |
ляющих символ, но возможности кодировать символы начинают превы- |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
данную кодировку. Тем не менее кодировка довольно |
шать ограничения в 256 или 65 536 значений, и можно закодировать лю- |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
компактно ужимает текст, содержит защиту от оши- |
бой символ из таблицы Юникода. Выгодно отличающийся от собратьев |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
бок чтения и, главное, интернациональна: любой че- |
UTF-32 менее популярен, ввиду избыточности представления данных, |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
ловек в любой точке мира увидит одни и те же сим- |
что критично при большом объеме текста. |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
волы из таблицы Юникода, если будет читать строку, |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
закодированную в UTF-8. Конечно, за исключением |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
случая, когда пытается интерпретировать эту строку |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
в другой кодировке, все помнят «кракозябры» при по- |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
пытке открыть кириллицу в UTF-8 как текст в кодиров- |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
ке по умолчанию в Windows 1251. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
УСТРОЙСТВООДНОБАЙТНОГОЮНИКОДА |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
Устроена кодировка UTF-8 весьма занятно. Вот ос- |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
новные принципы: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
1. |
|
|
Символ кодируется последовательностью байтов, |
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
в каждом байте лидирующие биты кодируют по- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
зицию байта в последовательности, а для первого |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
байта еще и длину последовательности. Например, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
так выглядит в UTF-8 символ Я: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[1101 0000] [1010 1111] |
|
При склейке, как видно, можно получить число, кодируемое 11 битами, то есть вплоть |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
до 0x7FF символа таблицы Юникода. Этого вполне хватает для символов кириллицы, рас- |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
положенной в пределах от 0x400 до 0x530. При склейке символа Я из примера получится |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
2. |
|
Байты последовательности, начиная со второго, |
код: |
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
всегда начинаются с битов 10, соответственно, пер- |
1 0000 10 1111 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вый байт последовательности кода каждого сим- |
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
вола начинаться с 10 не может. На этом строится |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
основная проверка корректности декодирования |
Как раз 0x42F — код символа Я в таблице символов Юникода. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
кода символа из UTF-8. |
|
Другими словами, если не работать с символами в строке, заменяя их другими сим- |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
3. Первый байт может быть единственным, тогда ли- |
волами из таблицы Юникода, то можно использовать кодировку UTF-8, она надежна, ком- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
|
дирующий бит равен 0 и символ соответствует коду |
пактна и совместима с типом char в том плане, что элементы строк совпадают по размеру |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
ASCII, поскольку для кодирования остается 7 млад- |
с байтом, но не обязательно являются при этом символами. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ших бит. |
|
Собственно, именно эффективностью и популярностью кодировки UTF-8 и обуслов- |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
4. |
|
|
Если символ не ASCII, то первые биты содержат |
лено насильственное введение однобайтового wchar_t в Android NDK, разработчики при- |
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
|
столько единиц, сколько байтов в последователь- |
зывают использовать UTF-8, а «широкие» строки не признают как жизнеспособный вид. |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
ности, включая лидирующий байт, после чего идет |
С другой стороны, Google не так давно отрицал даже исключения в C++, однако весь мир |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
0 как окончание последовательности единиц и по- |
не переспоришь, будь ты хоть трижды Google, и обработку исключений пришлось под- |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
том уже значащие биты первого байта. Как видно |
держать. Что касается wchar_t символов с размером в один байт, то множество библиотек |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
из приведенного примера, кодирование символа |
уже привыкло к мытарствам с типом wchar_t и дублируют «широкий» функционал обра- |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
Я занимает 2 байта, это можно распознать по стар- |
боткой обычных байтовых строк. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
шим двум битам первого байта последовательно- |
ПИШЕМПО-РУССКИВКОДЕ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
сти. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5. |
|
Все значащие биты склеиваются в единую по- |
Беды и дискриминация по языковому признаку начинаются, когда мы пытаемся исполь- |
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
следовательность битов и уже интерпретируются |
зовать в коде строку на языке, отличном от ASCII. Так, Visual Studio под Windows создает |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
как число. Например, для любого символа, коди- |
все файлы в кодировке файловой системы по умолчанию (1251), и при попытке открыть |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
руемого двумя байтами, значащие биты я условно |
код со строками по-русски в том же Linux с кодировкой по умолчанию UTF-8 получим кучу |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
помечу символом x: |
|
непонятных символов вместо исходного текста. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
[110x xxxx] [10xx xxxx] |
|
Ситуацию частично спасает пересохранение исходников в кодировке UTF-8 с обяза- |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
тельным символом BOM, без него Visual Studio начинает интерпретировать «широкие» |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
строки с кириллицей весьма своеобразно. Однако, указав BOM (Byte Order Mark — мет- |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
ка порядка байтов) кодировки UTF-8 — символ, кодируемый тремя байтами 0xEF, 0xBB |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
и 0xBF, мы получаем узнавание кодировки UTF-8 в любой системе. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
BOM — стандартный заголовочный набор байтов, нужный для распознавания коди- |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
ровки текста в Юникоде, для каждой из кодировок UTF он выглядит по-разному. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
UTF — по сути бай- |
Не стесняйся использовать родной язык в программе. Даже если тебе придется ло- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
кализовывать ее в другие страны, механизмы интернационализации помогут превратить |
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
товое представление |
любую строку на одном языке в любую строку на другом. Разумеется, это в случае, если |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
продукт разрабатывается в русскоязычном сегменте. |
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
текста, использующее |
Старайся использовать «широкие» строки как для строковых констант, так и для хра- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
нения и обработки промежуточных текстовых значений. Эффективная замена символов, |
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
коды символов из та- |
а также совпадение количества элементов в строке с количеством символов дорогого |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
стоит. Да, до сих пор не все библиотеки научились работать с «широкими» символами, |
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
блицы Юникода |
|
даже в Boost попадается целый ряд библиотек, где поддержка широких строк сделана |
|
|
|
|
|
|
|
|||||||||
|
|
|
|
|
|
|
небрежно, но ситуация исправляется, во многом благодаря разработчикам, пишущим |
|
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
|
C |
|
E |
|
|
|
|
|
|
|
C |
|
E |
|
|
|
||||||
|
|
X |
|
|
|
|
|
|
|
|
|
X |
|
|
|
|
|
|
||||||
|
- |
|
|
|
|
|
d |
|
|
|
- |
|
|
|
|
|
d |
|
||||||
|
F |
|
|
|
|
|
|
|
i |
|
|
|
F |
|
|
|
|
|
|
|
i |
|
||
|
|
|
|
|
|
|
|
t |
|
|
|
|
|
|
|
|
|
|
t |
|
||||
P |
D |
|
|
|
|
|
|
|
|
o |
|
|
P |
D |
|
|
|
|
|
|
|
|
o |
|
|
|
|
|
NOW! |
r |
|
|
|
|
|
|
NOW! |
r |
|||||||||||
|
|
|
|
|
BUY |
|
|
|
|
|
|
|
|
BUY |
|
|
||||||||
|
|
|
|
to |
|
|
|
|
|
|
|
|
|
|
|
to |
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
Грустная история забытых символов |
|
|
|
|
|
|
|
|
|
|
|
|
||
w |
|
|
|
|
ХАКЕР m12 /191/ 2014 |
|
w |
|
|
|
|
|
|
|
|
|
m |
|||||||
w Click |
|
|
|
w117Click |
|
|
|
|
|
o |
||||||||||||||
|
w |
|
|
|
|
|
|
|
|
o |
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
|
. |
|
|
|
|
|
|
.c |
|
|
|
. |
|
|
|
|
|
|
.c |
|
||||
|
|
p |
df |
|
|
|
|
e |
|
|
|
|
p |
df |
|
|
|
|
e |
|
||||
|
|
|
|
|
g |
|
|
|
|
|
|
|
|
|
g |
|
|
|
||||||
|
|
|
|
|
n |
|
|
|
|
|
|
|
|
|
|
n |
|
|
|
|
||||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
|
|
-x cha |
|
|
|
|
|
||||
|
|
|
|
|
|
Не обольщайся: писать названия констант и переменных, а также на- |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
звания функций кириллицей — все же не самая хорошая практика :) |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
ошибки в трекер библиотеки. Не стесняйся и ты фиксиро- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вать ошибки на сайте разработчика библиотеки. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Писать названия констант и переменных, а также названия |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
функций кириллицей все же не нужно. Одно дело — выводить |
Наиболее популярная библиотека |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
строковые литералы на родном языке, другое — писать код, |
именно libiconv, однако в ней ис- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
постоянно переключая раскладку. Не самый лучший вариант. |
пользуются исключительно пара- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
РАЗЛИЧАЕМТИП«БАЙТЫ»ИТИП«ТЕКСТ» |
метры char*. Это не должно пугать, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
в любом случае массив чисел любой |
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
Главное, что нужно уметь и иметь в виду, — что тип «текст» |
битности — это всего лишь набор |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
в корне отличается от типа «набор байтов». Если мы гово- |
байтов. Следует, однако, помнить |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
рим о строке сообщения, то это текст, а если о текстовом |
про направление двубайтовых и бо- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
файле в некоторой кодировке, то это набор байтов, который |
лее чисел. То есть в каком порядке |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
можно вычитать как текст. Если по сети нам приходят тексто- |
в байтовом массиве представлены |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вые данные, то они приходят к нам именно байтами, вместе |
байты — компоненты числа. Раз- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
с указанием кодировки, как из этих байтов получить текст. |
личают Big-endian и Little-endian |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Если посмотреть на Python 3 в сравнении с Python 2, |
соответственно. |
Общепринятый |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
то третья версия совершила по-настоящему серьезный |
порядок представления чисел в по- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
скачок в развитии, разделив эти два понятия. Крайне ре- |
давляющем большинстве машин — |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
комендую даже опытному C/C++ разработчику поработать |
Little-endian: сначала идет младший |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
немного в Python 3, чтобы ощутить всю глубину, с которой |
байт, а в конце старший байт числа. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
произошло разделение текста и байтов на уровне языка |
Big-endian знаком тем, кто работа- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
в Python. Фактически текст в Python 3 отделен от понятия ко- |
ет с протоколами передачи данных |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
дировки, что для разработчика C/C++ звучит крайне непри- |
по сети, где числа принято пере- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вычно, строки в Python 3 отображаются одинаково в любой |
давать начиная со старшего байта |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
точке мира, и если мы хотим работать с представлением |
(часто содержащего служебную ин- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
этой строки в какой-либо кодировке, то придется преобразо- |
формацию) и кончая младшим. Сле- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
вать текст в набор байтов, с указанием кодировки. При этом |
дует быть аккуратным и помнить, |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
внутреннее представление объекта типа str, по сути, не так |
что UTF-16, UTF-16BE и UTF-16LE — |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
важно, как понимание, что внутреннее представление сохра- |
не одно и то же. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
нено в Юникоде и готово к преобразованию в любую коди- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ровку, но уже в виде набора байтов типа bytes. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
В C/C++ подобный механизм нам мешает ввести отсутствие такой роскоши, как по- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
теря обратной совместимости, которую позволил себе Python 3 относительно второй |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
версии. Одно лишь разделение типа char на аналог wchar_t и byte в одной из следующих |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
редакций стандарта приведет к коллапсу языка и потере совместимости с непомерным |
icu::UnicodeString text(source_bytes, |
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
количеством уже написанного кода на С/С++. Точнее, всего, на чем ты сейчас работаешь. |
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
ВЕСЕЛЫЕПЕРЕКОДИРОВКИ |
source_encoding); |
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
Итак, исходная проблема осталась нерешенной. У нас по-прежнему есть однобайтовые |
Таким образом, предлагается полностью от- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
кодировки, как UTF-8, так и старые и недобрые однобайтовые кодировки вроде кодиров- |
казаться от типа wchar_t. Проблема, однако, в том, |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
ки Windows 1251. С другой стороны, мы задаем строковые константы широкими строками |
что внутреннее представление Юникода для такой |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
и обрабатываем текст через wchar_t — «широкие» символы. |
строки установлено в два байта, что влечет за собой |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
|
|
|
|
Здесь нам на помощь придет механизм перекодировок. Ведь, зная кодировку набо- |
проблему в случае, когда код за эти два байта выхо- |
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
ра байтов, мы всегда сможем преобразовать его в набор символов wchar_t и обратно. |
дит. Кроме того, интерфейс icu::UnicodeString полно- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
Не спеши только самостоятельно создавать свою библиотеку перекодировки, я понимаю, |
стью несовместим со стандартным wstring, однако |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
что коды символов любой кодировки сейчас можно найти за минуту, как и всю табли- |
использование ICU — хороший вариант для С++ раз- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
цу кодов Юникода последней редакции. Однако библиотек перекодировки достаточно |
работчика. |
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
и без этого. Есть кросс-платформенная библиотека libiconv, под лицензией LGPL, самая |
Кроме того, есть пара стандартных функций |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
популярная на сегодняшний день для кросс-платформенной разработки. Перекодировка |
mbstowcs и wcstombs. В общем и целом при пра- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
сводится к нескольким инструкциям: |
вильно заданной локали они, соответственно, преоб- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
iconv_t conv = iconv_open("UTF-8","CP1251"); |
разуют (мульти-) байтовую строку в «широкую» и на- |
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
|
оборот. Расшифровываются сокращения mbs и wcs |
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
iconv(conv, &src_ptr, &src_len, &dst_ptr, &dst_len); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
iconv_close(conv); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
Соответственно, сначала создание обработчика перекодировки из одной кодировки |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
в другую, затем сама операция перекодировки одного набора байтов в другой (даже если |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
один из наборов байтов на самом деле байты массива wchar_t), после чего обязательное |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
закрытие созданного обработчика перекодировки. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
Есть также и более амбициозная библиотека ICU, которая предоставляет как C++ ин- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
терфейс для работы с перекодировкой, так и специальный тип icu::UnicodeString для хра- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
нения непосредственно текста в представлении Юникода. Библиотека ICU также является |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
кросс-платформенной, и вариантов ее использования предоставляется на порядок боль- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
ше. Приятно, что библиотека сама заботится о создании, кешировании и применении об- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
работчиков для перекодировки, если использовать C++ API библиотеки. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
Например, чтобы создать строку в Юникоде, предлагается использовать обычный |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
конструктор класса icu::UnicodeString: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
|
|
|
|
|
|
|
hang |
e |
|
|
|
|
|
||
|
|
|
C |
|
E |
|
|
|
|
|
|
|
|
|
C |
|
E |
|
|
|
||||||
|
|
X |
|
|
|
|
|
|
|
|
|
|
|
X |
|
|
|
|
|
|
||||||
|
- |
|
|
|
|
|
d |
|
|
|
|
|
- |
|
|
|
|
|
d |
|
||||||
|
F |
|
|
|
|
|
|
|
t |
|
|
|
|
|
F |
|
|
|
|
|
|
|
t |
|
||
|
D |
|
|
|
|
|
|
|
|
i |
|
|
|
|
|
D |
|
|
|
|
|
|
|
|
i |
|
|
|
|
|
|
|
|
|
|
r |
|
|
|
|
|
|
|
|
|
|
|
|
r |
||||
P |
|
|
|
|
|
NOW! |
o |
|
|
|
|
P |
|
|
|
|
|
NOW! |
o |
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||||
|
|
|
|
|
BUY |
|
|
|
|
|
|
|
|
|
|
BUY |
|
|
||||||||
|
|
|
|
to |
|
|
|
|
|
|
|
|
|
|
|
|
|
to |
|
|
|
|
|
|
||
w Click |
|
ХАКЕР m |
12 /191/ 2014 |
|
|
|
|
|
|
|
|
|
|
|
|
m |
||||||||||
|
|
|
|
w119Click |
|
|
|
|
|
|
||||||||||||||||
w |
|
|
|
|
|
|
|
|
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
|
|
||
|
w |
|
|
|
|
|
|
|
|
o |
|
|
|
|
|
w |
|
|
|
|
|
|
|
|
o |
|
|
. |
|
|
|
|
g |
.c |
|
|
|
|
|
. |
|
|
|
|
g |
.c |
|
||||||
|
|
p |
|
|
|
|
|
|
|
|
|
|
|
|
p |
|
|
|
|
|
|
|
||||
|
|
|
df |
|
|
n |
e |
|
|
|
|
|
|
|
df |
|
|
n |
e |
|
||||||
|
|
|
|
-xcha |
|
|
|
|
|
|
|
|
|
|
|
|
-x cha |
|
|
|
|
|
||||
|
|
|
|
|
|
char const* byte_c_str(char const* encoding) const; |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
wchar_t const* wide_c_str() const; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
|
Реализация сводится к вызову c_str() у результатов byte_string и wide_string |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
соответственно. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
Можно считать кодировкой по умолчанию для байтовых строк UTF-8, это го- |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
раздо лучше, чем пытаться работать с системной кодировкой по умолчанию, так |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
код в зависимости от системы будет работать по-разному. Введя ряд дополни- |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
тельных перегрузок без указания кодировки при работе с байтовыми строками, |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
мы также получаем возможность переопределить оператор присвоения: |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
// в |
од |
ов |
UTF-8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
text& operator = (std::string const& byte_string); |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
text& operator = (std::wstring const& wide_string); |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
Нужно также не забыть о перегрузке операторов + и +=, но в целом остальные |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
операции можно уже сводить к аргументу и результату типа text, универсальному |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
значению, предоставляющему текст вне зависимости от кодировки. |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
Разумеется, Академия C++ не была бы академией, если бы я не предложил |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
тебе теперь реализовать класс текста самостоятельно. Попробуй создать класс |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
text на основе материала этой статьи. Реализация должна удовлетворять двум |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
простым свойствам: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
• Классом должно быть удобнее пользоваться, чем стандартными строками, |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
вдобавок класс предоставляет совместимость либо взаимное преобразова- |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
ние с типами std::string, std::wstring, char const* |
wchar_t const*. |
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
• Класс подразумевает максимальную оптимизацию, работа со строками |
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
не должна быть дороже, чем при работе со стандартными std::string |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
и std::wstring. То есть никаких неявных перекодировок, пока API явно |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
не подразумевает перекодировку содержимого, иначе классом никто не будет |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
пользоваться. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
Здесь как раз имеет смысл обработать дополнительно неконстантный |
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
operator |
-> для сброса кеша со строками, однако оставляю это на усмотрение |
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
разработчика. То есть тебя. Удачи! |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
ЧТОМЫПОЛУЧАЕМ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
Реализовав класс text, мы получим абстракцию от множества кодировок, все, |
ние у нас всегда UTF-32 при распаковке символов и мы нигде |
|
|
|
|
|
|
|
||||||||||||
|
|
|
|
|
|
что нам потребуется, — одна перегрузка от класса text. Например, так: |
не завязаны на платформозависимый wchar_t. |
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
text to_json() const; |
|
Итого: у нас есть совместимость либо взаимоконвертация |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
со стандартными типами, а значит, и упрощение поддержки |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
void from_json(text const& source); |
Юникода на стороне кода, написанного на С++. Ведь если мы |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
пишем высокоуровневую логику на C++, меньше всего нам |
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
Нам больше не нужно множество перегру- |
хочется получить проблемы при использовании wchar_t сим- |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
зок от std::string и std::wstring, не нуж- |
волов и кучи однообразного кода при обработке и перекоди- |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
но будет переходить на поддержку «широ- |
ровке текста. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ких» строк, достаточно заменить в API ссылки |
При том что сама перекодировка уже реализована в тех |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
на строки на text, и получаем Юникод автома- |
же ICU4C и libiconv, алгоритм для внутренней работы класса |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
том. Вдобавок мы получаем отличное кросс- |
text довольно прост. Дерзай, и, может, уже завтра именно твоя |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
платформенное поведение, вне зависимости |
библиотека работы с текстом будет использоваться повсюду |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
от того, какую библиотеку мы выбрали в ка- |
в качестве высокоуровневой абстракции при обработке любых |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
честве движка перекодировки, — ICU4C или |
текстовых данных, от простого JSON с клиента до сложных тек- |
|
|
|
|
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
libiconv, ввиду того, что внутреннее представле- |
стовых структур со стороны различных баз данных. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
В итоге у нас есть совмести- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
мость либо взаимоконверта- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
ция со стандартными ти- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
пами, а значит, и упрощение |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
поддержки Юникода на сторо- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
не кода, написанного на С++ |
|
|
|
|
|
|
|
|
|
|
|
|
|