Символы для ников

III. What to do right now

Here’s your to-do list:

  1. «char» no longer means character
    I hereby recommend referring to character codes in C programs using a
    32-bit unsigned integer type. Many platforms provide a «wchar_t» (wide
    character) type, but unfortunately it is to be avoided since some compilers
    allot it only 16 bits—not enough to represent Unicode. Wherever you
    need to pass around an individual character, change «char» to «unsigned int»
    or similar. The only remaining use for the «char» type is to mean «byte».

  2. Get UTF-8-clean
    To take advantage of UTF-8, you’ll have to treat bytes higher than 127 as
    perfectly ordinary characters. For example, say you have a routine that
    recognizes valid identifier names for a programming language. Your existing
    standard might be that identifiers begin with a letter:

    int valid_identifier_start(char ch)
    {
        return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z'));
    }
    

    If you use UTF-8, you can extend this to allow letters from other languages
    as follows:

    int valid_identifier_start(char ch)
    {
        return ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') ||
                ((unsigned char)ch >= 0xC0));
    }
    

    A UTF-8 sequence can only start with values 0xC0 or greater, so that’s what
    I used for checking the start of an identifier. Within an identifier, you
    would also want to allow characters >= 0x80, which is the range of
    UTF-8 continuation bytes.

    Most C string library routines still work with UTF-8, since they only scan
    for terminating NUL characters. A notable exception is strchr(), which
    in this context is more aptly named «strbyte()». Since you will be passing
    character codes around as 32-bit integers, you need to replace this with
    a routine such as my u8_strchr() that can scan UTF-8 for a given character.
    The traditional strchr() returns a pointer to the location of the found
    character, and u8_strchr() follows suit. However, you might want to know
    the index of the found character, and since u8_strchr() has to scan through
    the string anyway, it keeps a count and returns a character index as well.

    With the old strchr(), you could use pointer arithmetic to determine the
    character index. Now, any use of pointer arithmetic on strings is likely
    to be broken since characters are no longer bytes. You’ll have to find and
    fix any code that assumes «(char*)b — (char*)a» is the number of characters
    between a and b (though it is still of course the number of bytes
    between a and b).

  3. Interface with your environment
    Using UTF-8 as an internal encoding is now widespread among
    C programmers. However, the environment your program runs in will not
    necessarily be nice enough to feed you UTF-8, or expect UTF-8 output.

    The functions mbstowcs() and wcstombs() convert from and to locale-specific
    encodings, respectively. «mbs» means multibyte string (i.e. the locale-specific
    string), and «wcs» means wide character string (universal 4-byte characters).
    Clearly, if you use wide characters internally, you are in luck here. If you
    use UTF-8, there is a chance that the user’s locale will be set to UTF-8 and
    you won’t have to do any conversion at all. To take advantage of that
    situation, you will have to specifically detect it (I’ll provide a function
    for it). Otherwise, you will have to convert from multibyte to wide to UTF-8.

    Version 1.6 (1.5.x while in development) of the
    FOX toolkit uses UTF-8 internally,
    giving your program a nice all-UTF-8-all-the-time environment. GTK2 and Qt
    also support UTF-8.

  4. Modify APIs to discourage O(n^2) string processing
    The idea of non-constant-time string indexing may worry you. But when
    you think about it, you rarely need to specifically access the nth character
    of a string. Algorithms almost never need to make requests like «Quick! Get
    me the 6th character of this piece of text!» Typically, if you’re accessing
    characters you’re iterating over the whole string or most of it. UTF-8 is
    simple enough to process that iterating over characters takes essentially
    the same time as iterating over bytes.

    In your own code, you can use my u8_inc() and u8_dec() to move through
    strings. If you develop libraries or languages, be sure to expose some kind
    of inc() and dec() API so nobody has to move through a string by repeatedly
    requesting the nth character.

Переход к Unicode

Развитие интернета, увеличение количества компьютеров и удешевление памяти привели к тому, что проблемы, которые доставляла путаница в кодировках, стали перевешивать некоторую экономию памяти. Особенно ярко это проявлялось в интернете, когда текст написанный на одном компьютере должен был корректно отображаться на многих других устройствах. Это доставляло огромные проблемы как программистам, которые должны были решать какую кодировку использовать, так и конечным пользователям, которые не могли получить доступ к интересующим их текстам.

В результате в октябре 1991 года появилась первая версия одной общей таблицы символов, названной Unicode. Она включала в себя на тот момент 7161 различный символ из 24 письменностей мира.

В Unicode постепенно добавлялись новые языки и символы. Например, в версию 1.0.1 в середине 1992 года добавили более 20 000 идеограмм китайского, японского и корейского языков. В актуальной на текущий момент версии содержится уже более 143 000 символов.

Small FAQ

What conversions does this do?

This toy only converts characters from the ASCII range. Characters are
only converted on a one-to-one basis; no combining
characters (eg U+20DE COMBINING ENCLOSING SQUARE), many to one (eg
ligatures), or context varying (eg Braille)
transformations are done.

Current true transforms:circled, negative circled, Asian fullwidth, math bold, math bold Fraktur, math bold italic, math bold script, math double-struck, math monospace, math sans, math sans-serif bold, math sans-serif bold italic, math sans-serif italic, parenthesized, regional indicator symbols, squared, negative squared, and tagging text (invisible for hidden metadata tagging).
Psuedo transforms (made by picking and choosing from here and there in Unicode)
available:acute accents, CJK based, curvy variant 1, curvy variant 2, curvy variant 3, faux Cyrillic, Mock Ethiopian, math Fraktur, rock dots, small caps, stroked, subscript (many missing, no caps), superscript (some missing), inverted, and reversed (an incomplete alphabet, better with CAPITALS).

Capitalization preserved where available.

What makes an alphabet «psuedo»?

One or more of the letters transliterated has a different meaning or source than intended. In the non-bold version of Fraktur, for example, several letters are «black letter» but most are «mathematical fraktur». In the Faux Cyrillic and Faux Ethiopic, letters are selected merely based on superficial similarities, rather than phonetic or semantic similarities.

What is «CJK»?

CJK is a collective term for the Chinese, Japanese, and Korean languages, all of which use Chinese characters and derivatives in their writing systems.

What is «Fullwidth»?

These are «Roman» letters that are the same width as Japanese characters and are typically used when mixing English and Japanese.

What is the deal with «Tag»?

«Tags» is a Unicode block containing characters for invisibly tagging texts by language. The tag characters are deprecated in favor of markup. All printable ASCII have a tag version. Properly rendered, they have both no glyph and zero width. Note that sometimes zero width text cannot be easily copied.

What is the deal with «Regional Indicator»?

This block of characters is intended to indicate a global region, eg «France». As such some tools use short sequences of Regional Indicators to encode flags. The idea is that the same two-letter country codes used in domain names would be mapped into this block to represent that region, eg, with a flag. So U+1F1EB («Symbol Letter F») and U+1F1F7 («Symbol Letter R») are the way the French flag might be encoded: (results will vary with browser).


A Unicode Toy 2009-2016 Eli the Bearded

Кодировка windows-1251

Графические системы развивались, у них необходимость в псевдографике пропадала. Поэтому ее убрали. И возникла целая группа расширенных кодировок ascii без псевдографики. У них принцип такой же: 1 символ = 1 байт. А вместо псевдографики появились символы, которые описывают целую группу кириллических языков (украинский, болгарский, сербский, белорусский). Т.е. здесь мы видим целую группу кириллических языков. Поэтому эта кодировка часто называется кириллицей.

Все вышеописанные кодировки — из разряда ASCII. А как быть с азиатскими языками, где не 256 символов, а тысячи? Поэтому изначально там были свои кодировки. Но вскоре компания Microsoft инициировала создание консорциума для решения проблемы кодировок. Консорциум называется unicode (www.unicode.org). Он объединяет в себе сегодня сотни компаний.

И в результате работы консорциума возникали такие кодировки:

  • Кодировка UTF-32. 32 — это количество бит, которое используется для кодирования. И здесь можно описать миллиарды символов. Но есть проблема — в 4 раза увеличивается размер документа, использующего группы европейские языки. Такое не могли себе позволить.
  • Кодировка UTF-16. Эта кодировка была принята в качестве базового пространства для всех символов, которые у нас используются. Здесь используется 2 байта на 1 символ. Всего можно закодировать до 1 миллиона символов. Но был небольшой недостаток для англоязычных программистов, все документы увеличивались в 2 раза по размеру. И придумали кодировку переменной длины — utf-8.
  • Кодировка UTF-8. Это кодировка переменной длины, т.е. каждый символ может быть закодирован от 1 до 6 байт. На практике используется диапазон 1-4 байт, т.к. за 4 байтами ничего не лежит. Все латинские символы из кодировки ascii кодируются в 1 байт, кириллические символы кодируются в 2 байта, грузинские символы — в 3 байта. Иероглифы — в 4 байта. Всего можно закодировать до 1 миллиона символов.

Примеры[править]

Если записать строку ‘hello мир’ в файл exampleBOM, а затем сделать его hex-дамп, то можно убедиться в том, что разные символы кодируются разным количеством байт. Например, английские буквы,пробел, знаки препинания и пр. кодируются одним байтом, а русские буквы — двумя

Код на pythonправить

#!/usr/bin/env python
#coding:utf-8
import codecs
f = open('exampleBOM','w')
b = u'hello мир'
f.write(codecs.BOM_UTF8)
f.write(b.encode('utf-8'))
f.close()

hex-дамп файла exampleBOMправить

Символ BOM h e l l o Пробел м и р
Код в UNICODE EF BB BF 68 65 6C 6C 6F 20 D0 BC D0 B8 D1 80
Код в UTF-8 11101111 10111011 10111111 01101000 01100101 01101100 01101100 01101111 00100000 11010000 10111100 11010000 10111000 11010001 10000000

Библиотека преобразований Unicode-кодировок

В сопутствующий этой статье пакет исходного кода включен пример компилируемого C++-кода. Это повторно используемый код, без ошибок компилируемый в Visual C++ при уровне предупреждений 4 (/W4) в 32- и 64-разрядных сборках. Он реализован как библиотека C++ в виде только заголовочных файлов. По сути, этот модуль преобразования Unicode-кодировок состоит из двух заголовочных файлов: utf8except.h и utf8conv.h. Первый содержит определение C++-класса исключения, используемого для уведомления об ошибке при преобразованиях Unicode-кодировок. Второй реализует собственно функции преобразования Unicode-кодировок.

Заметьте, что utf8except.h содержит только кросс-платформенный C++-код; это делает возможным захват исключения при преобразовании кодировки UTF-8 в любых местах ваших проектов на C++, включая те части кода, которые не специфичны для Windows. Напротив, utf8conv.h содержит C++-код, специфичный для Windows, поскольку он напрямую взаимодействует с границей Win32 API.

Для повторного использования этого кода в ваших проектах просто включайте директивой #include эти заголовочные файлы. Сопутствующий пакет исходного кода содержит дополнительный файл, реализующий некоторые наборы тестов.

Другие решения

Изначально компьютеры были предназначены для американского рынка и использовали Ascii — американский код для обмена информацией. Это были 7-битные коды, и только основные английские буквы и несколько знаков препинания, а также коды на нижнем конце, предназначенные для управления терминалами для бумаги и чернил принтера.
Это стало неадекватным, так как компьютеры развивались и начали использоваться для языковой обработки так же, как для числовой работы. Первое, что произошло, было то, что были предложены различные расширения до 8 бит. Это может либо покрыть большинство украшенных европейских символов (акценты и т. Д.), Либо дать серию базовой графики, подходящей для создания меню и панелей, но вы не можете достичь того и другого. Не было еще способа представить нелатинские наборы символов, такие как греческий.
Таким образом, был предложен 16-битный код под названием Unicode. Microsoft приняла это очень рано и изобрела WCHAR WCHAR (он имеет различные идентификаторы) для хранения международных символов. Однако выяснилось, что 16 бит недостаточно для общего использования всех глифов, а консорциум Unicode исключает некоторые незначительные несовместимости с 16-битным кодовым набором Microsoft.

Таким образом, Unicode может быть серией 16-битных целых чисел. Это строка wchar. Текст Ascii теперь содержит нулевые символы между старшими байтами, поэтому вы не можете передать широкую строку функции expectign Ascii. Поскольку 16 битов было почти, но не совсем достаточно, был также создан 32-битный набор Unicode.

Однако, когда вы сохраняли Unicode в файл, это создавало проблемы, было ли это 16-битным 32-битным> И было ли это с прямым порядком байтов или с прямым порядком байтов. Таким образом, флаг в начале данных был предложен, чтобы исправить это. Проблема заключалась в том, что содержимое файла по памяти больше не соответствовало содержимому строки.

C ++ std:; string была спроектирована так, чтобы она могла использовать базовые символы или один из широких типов, почти всегда на практике 16-битное кодирование Microsoft, близкое к юникодовому.

UTF-8 был изобретен, чтобы прийти на помощь. Это многобайтовое кодирование переменной длины, в котором используется тот факт, что ascii составляет всего 7 бит. Таким образом, если старший бит установлен, это означает, что у вас есть два, три или четыре байта в символе. Сейчас очень большое количество строк — это английский язык или, в основном, удобочитаемые числа, так что, по сути, ascii. Эти строки такие же в Ascii, как и в UTF-8, что значительно облегчает жизнь. У вас нет проблем с порядком байтов. У вас есть проблема, заключающаяся в том, что вы должны декодировать UTF-8 в кодовые точки с помощью не совсем тривиальной функции, и не забывайте увеличивать свою позицию чтения на правильное число байтов.

UTF-8 — действительно ответ, но другие кодировки все еще используются, и вы столкнетесь с ними.

-1

Решение

Для ваших целей, находя и распечатывая значение каждого символа, вы, вероятно, захотите использовать потому что он не имеет многобайтовых строк или суррогатных пар и может быть преобразован в десятичные значения просто путем приведения к , Я хотел бы сослаться на пример, который я написал, но звучит так, как будто вы хотите решить эту проблему самостоятельно.

C ++ 14 напрямую поддерживает типы , а также в дополнение к наследию иногда это означает UCS-32, иногда UTF-16LE, иногда UTF-16BE, иногда что-то другое. Он также позволяет хранить строки во время выполнения, независимо от того, в каком наборе символов вы сохранили исходный файл, в любом из этих форматов с , а также префиксы и тому Юникод побег как запасной вариант. Для обратной совместимости вы можете закодировать UTF-8 шестнадцатеричными управляющими кодами в массиве ,

Таким образом, вы можете хранить данные в любом формате, который вы хотите. Вы также можете использовать аспект , которые должны поддерживать все локали. Есть также многобайтовые строковые функции в а также ,

Я настоятельно рекомендую вам хранить все новые внешние данные в UTF-8. Это включает в себя ваши исходные файлы! (Досадно, что некоторые старые программы все еще не поддерживают его.) Также может быть удобно использовать тот же набор символов внутри, что и в ваших библиотеках, который будет UTF-16 () в Windows. Если вам нужны символы фиксированной длины, которые могут содержать любую кодовую точку без особых случаев, будет удобно.

2

II. The C library

«Multibyte character» or «multibyte string» refers to text in
one of the many (possibly language-specific) encodings that exist throughout
the world. A multibyte character does not necessarily require more than one
byte to store; the term is merely intended to be broad enough to encompass
encodings where this is the case. UTF-8 is in fact only one such
encoding; the actual encoding of user input is determined by the user’s current
locale setting (selected as an option in a system dialog or stored as an
environment variable in UNIX). Strings you get from the user will be in
this encoding, and strings you pass to printf() are supposed to be as well.
Strings within your program can of course be in any encoding you want, but
you might have to convert them for proper display.

«Wide character» or «wide character string» refers to text where
each character is the same size (usually a 32-bit integer)
and simply represents a Unicode character
value («code point»). This format is a known common currency that allows you
to get at character values if you want to. The wprintf() family is able to
work with wide character format strings, and the «%ls» format specifier for
normal printf() will print wide character strings (converting them to the
correct locale-specific multibyte encoding on the way out).

The C library also provides functions like towupper() that can convert a
wide character from any language to uppercase (if applicable). strftime()
can format a date and time string appropriately for the current locale, and
strcoll() can do international sorting. These and other functions that
depend on locale must be initialized at the beginning of your program using

#include <locale.h>

int main()
{
    char *locale;

    locale = setlocale(LC_ALL, "");
    ...
}

Your encoding options

You are free to choose a string encoding for internal use in your program.
The choice pretty much boils down to either UTF-8, wide (4-byte) characters,
or multibyte.
Each has its advantages and disadvantages:

  • UTF-8

    • Pro: compatible with all existing strings and most existing code
    • Pro: takes less space
    • Pro: widely used as an interchange format (e.g. in XML)
    • Con: more complex processing, O(n) string indexing

    Wide characters

    • Pro: easy to process
    • Con: wastes space
    • Pro/Con: although you can use the syntax
      L"Hello, world."

      to easily include wide-character strings in C programs, the size of wide
      characters is not consistent across platforms (some incorrectly use 2-byte
      wide characters)

    • Con: should not be used for output, since spurious zero bytes and other
      low-ASCII characters with common meanings (such as ‘/’ and ‘\n’) will likely
      be sprinkled throughout the data.

    Multibyte

    • Pro: no conversions ever needed on input and output
    • Pro: built-in C library support
    • Pro: provides the widest possible internationalization, since in rare
      cases conversion between local encodings and Unicode does not work well
    • Con: strings are opaque
    • Con: perpetuates incompatibilities. For example, there are three major
      encodings for Russian. If one Russian sends data to another through your
      program, the recipient will not be able to read the message if his or her
      computer is configured for a different Russian encoding. But if your program
      always converts to UTF-8, the text is effectively normalized so that it will
      be widely legible (especially in the future) no matter what encoding it
      started in.

In this article I will advocate and give explicit instruction on using
UTF-8 as an internal string encoding. Many Linux users already set their
environment to a UTF-8 locale, in which case you won’t even have to do
any conversions. Otherwise you will have to convert multibyte to
wide to UTF-8 on input, and back to multibyte on output. Nevertheless,
UTF-8 has its advantages.

Кодировки на основе Unicode

Unicode можно себе представить как огромную таблицу символов. В памяти компьютера записываются не сами символы, а номера из таблицы. Записывать их можно разными способами. Именно для этого на основе Unicode разработаны несколько кодировок, которые отличаются способом записи номера символа Unicode в виде набора байт. Они называются UTF — Unicode Transformation Format. Есть кодировки постоянной длины, например, UTF-32, в которой номер любого символа из таблицы Unicode занимает ровно 4 байта. Однако наибольшую популярность получила UTF-8 — кодировка с переменным числом байт. Она позволяет кодировать символы так, что наиболее распространённые символы занимают 1-2 байта, и только редко встречающиеся символы могут использовать по 4 байта. Например, все символы таблицы ASCII занимают ровно по одному байту, поэтому текст, написанный на английском языке с использованием кодировки UTF-8, будет занимать столько же места, как и текст, написанный с использованием таблицы символов ASCII.

На сегодняшний день Unicode является основной кодировкой, которую используют в работе все, кто связан с компьютерами и текстами. Unicode позволяет использовать сотни тысяч различных символов и отображать их одинаково на всех устройствах от мобильных телефонов до компьютеров на космических станциях.

Заключение

Unicode является стандартом де-факто для представления текста на любых языках в современном программном обеспечении. Unicode-текст можно кодировать в разнообразных форматах: два наиболее важных из них — UTF-8 и UTF-16. В C++-коде для Windows часто требуется преобразовывать строки между кодировками UTF-8 и UTF-16, так как Win32-функции с поддержкой Unicode используют UTF-16 в качестве “родной” Unicode-кодировки. Текст в кодировке UTF-8 удобно хранить в экземплярах STL-класса std::string, тогда как std::wstring хорошо подходит для хранения текста в кодировке UTF-16 в C++-коде для Windows, ориентированном на компилятор Visual C++.

Win32-функции MultiByteToWideChar и WideCharToMultiByte позволяют выполнять преобразования Unicode-текста между кодировками UTF-8 и UTF-16. Я подробно описал шаблон использования функции MultiByteToWideChar, обернув ее в повторно используемую вспомогательную функцию на современном C++ для выполнения преобразований из UTF-8 в UTF-16. Обратное преобразование следует очень похожему шаблону, и повторно используемый C++-код, реализующий его, доступен в пакете кода, сопутствующем этой статье.

Джованни Диканио (Giovanni Dicanio) — программист со специализацией в области C++ и Windows, автор Pluralsight и обладатель звания Visual C++ MVP. Помимо программирования и создания учебных курсов, с удовольствием помогает другим на форумах и в сообществах, преданных C++. С ним можно связаться по адресу giovanni.dicanio@gmail.com. Также ведет блог на blogs.msmvps.com/gdicanio.

Выражаю благодарность за рецензирование статьи экспертам Дэвиду Крейви (David Cravey) и Марку Грегуа (Marc Gregoire).

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector