[Перевод] Этот восхитительный Юникод

b88144f6adfaa57502bbd588f27d09a7.jpg

Перед вами обновляемый список самых замечательных «вкусностей» Юникода, а также пакетов и ресурсов

Юникод — это потрясающе! До его появления международная коммуникация была изнурительной: каждый определял свой отдельный расширенный набор символов в верхней половине ASCII (так называемые кодовые страницы). Это порождало конфликты. Просто подумайте, что немцам приходилось договариваться с корейцами, где чья кодовая страница на 127 символа. К счастью, появился Юникод и унифицировал коммуникации. Стандарт Юникод 8.0 охватывает более 120 000 символов из более 129 письменностей. И современные, и древние, и до сих пор не расшифрованные. Юникод поддерживает текст слева направо и справа налево, наложение символов и включает самые разные культурные, политические, религиозные символы и эмодзи. Юникод потрясающе человечен, а его возможности сильно недооцениваются.


Какие символы входят в Стандарт Юникод?


Стандарт Юникод определяет коды для символов основных современных языков. Это европейские алфавитные письменности, ближневосточные письменности справа налево и многие письменности Азии.

Стандарт также содержит знаки пунктуации, диакритические знаки, математические символы, технические символы, стрелки, дингбаты, эмодзи и т. д. Он предоставляет коды для диакритических знаков, изменяющих знаки символов, такие как тильда (~). Они используются в сочетании с основными для представления акцентированных символов (например, ñ). В целом, Юникод версии 9.0 предоставляет коды для 128 172 символов из мировых алфавитов, наборов идеограмм и коллекций символов.

Большинство символов общего пользования помещаются в первые 64K кодовых точек, область кодового пространства, которая называется основной многоязычной плоскостью, или BMP для краткости. Есть ещё шестнадцать других дополнительных плоскостей, доступных для кодирования других символов, с более чем 850 000 неиспользуемых кодовых точек. Они могут пригодиться для добавления новых символов в будущие версии стандарта.

Стандарт Юникод также резервирует кодовые точки для частного использования. Вендоры или конечные пользователи могут назначать их в своих собственных системах для своих символов или использовать со специализированными шрифтами. На BMP находится 6400 кодовых точек для частного использования и ещё 131 068 дополнительных кодовых точек частного использования, если 6400 недостаточно для конкретных приложений.

Кодировки символов Юникода


Стандарты кодирования символов определяют не только идентичность каждого символа и его числовое значение или кодовую точку, но и то, как это значение представлено в битах.

Стандарт Юникод определяет три формы кодирования, которые позволяют передавать одни и те же данные: это байт, слово и двойное слово (то есть 8, 16 или 32 бит на единицу кода). Все три формы кодируют один и тот же общий набор символов и могут быть эффективно преобразованы друг в друга без потери данных. Консорциум Юникод полностью одобряет использование любой из этих форм кодирования в качестве согласованного способа реализации Стандарта Юникод.

UTF-8 популярен для HTML и подобных протоколов. UTF-8 — это способ преобразования всех символов Юникода в кодировку переменной байтовой длины. Его преимущество в том, что символы Юникода, соответствующие знакомому набору ASCII, имеют те же байтовые значения, что и ASCII, а символы Юникода, преобразованные в UTF-8, могут использоваться с большим количеством существующего программного обеспечения без серьёзной доработки ПО.

UTF-16 популярен во многих средах, где необходимо сбалансировать эффективный доступ к символам с экономичным хранением. Он достаточно компактен, и все часто используемые символы помещаются в один 16-битный кодовый блок, в то время как все остальные символы доступны через пары 16-битных кодовых блоков.

UTF-32 полезен там, где объём памяти не вызывает беспокойства, но требуется доступ к символам по единому коду фиксированной ширины. Здесь каждый символ Юникода кодируется в одном 32-разрядном кодовом блоке.

Все три формы кодирования требуют для каждого символа не более 4 байт (или 32 бит).

Поговорим о цифрах


Набор символов Юникода разделён на 17 основных сегментов (плоскостей), которые далее делятся на блоки. В каждой плоскости есть место для 65 536 (216) кодовых точек, что создаёт в сумме 1 114 112 кодовых точек. Есть две «плоскости частного использования» (№ 16 и № 17), которые выделяются для использования на усмотрение компаний/пользователей. В них 131 072 кодовые точки.
Первая плоскость называется основной многоязычной плоскостью или BMP. Она содержит кодовые точки от U+0000 до U+FFFF, то есть наиболее часто используемые символы. Остальные шестнадцать плоскостей (U+010000 → U+10FFFF) называются дополнительными или астральными.

Суррогатные пары UTF-16


Символы вне основной плоскости, как тетраграмматон, означающий центр (U+1D306), можно закодировать в UTF-16 только двумя 16-битными кодовыми единицами: 0xD834 0xDF06. Это называется суррогатной парой. Обратите внимание, что суррогатная пара представляет только один символ.

Первая кодовая единица суррогатной пары всегда находится в диапазоне от 0xD800 до 0xDBFF и называется верхней частью пары.

Вторая кодовая единица суррогатной пары всегда находится в диапазоне от 0xDC00 до 0xDFFF и называется нижней частью пары.

Матиас Байненс


Суррогатная пара: представление одного абстрактного символа, состоящего из последовательности двух 16-разрядных кодовых единиц, где первое значение пары является верхней суррогатной кодовой единицей, а второе — нижней суррогатной кодовой единицей. Суррогатные пары используются только в UTF-16.

Unicode 8.0 Глава 3.8 − Суррогаты


Вычисление суррогатных пар


Юникодовский символ «Куча дерьма» (U+1F4A9) в UTF-16 придётся кодировать как суррогатную пару, т. е. два суррогата. Чтобы преобразовать любую кодовую точку в суррогатную пару, используйте такой алгоритм (на JavaScript). Имейте в виду, что мы используем шестнадцатеричную нотацию.

 var High_Surrogate = function(Code_Point){ return Math.floor((Code_Point - 0x10000) / 0x400) + 0xD800 };
 var Low_Surrogate  = function(Code_Point){ return (Code_Point - 0x10000) % 0x400 + 0xDC00 };

 // Reverses The Conversion
 var Code_Point = function(High_Surrogate, Low_Surrogate){
	return (High_Surrogate - 0xD800) * 0x400 + Low_Surrogate - 0xDC00 + 0x10000;
 };
 > var codepoint = 0x1F4A9;   					// 0x1F4A9 == 128169
 > High_Surrogate(codepoint).toString(16)
 "d83d"  										// 0xD83D == 55357
 > Low_Surrogate(codepoint).toString(16)
 "dca9"  										// 0xDCA9 == 56489

 > String.fromCharCode(  High_Surrogate(codepoint) , Low_Surrogate(codepoint) );
  ""
> String.fromCodePoint(0x1F4A9)
  ""
 > '\ud83d\udca9'
  ""


Композиция и декомпозиция


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

Некоторые последовательности символов также можно представить в виде одного символа, который называется предварительно составленным символом (precomposed character), он же составной символ (composite character). Например, символ [ü] можно закодировать как единственную кодовую точку U+00FC или как базовый символ U+0075 (u), за которым следует несамостоятельный знак U+0308 (¨). Стандарт Юникод кодирует составные символы для совместимости с установленными стандартами, такими как Latin 1, который включает в себя множество составных символов, таких как [ü] и [ñ].

Составные символы можно разложить для согласованности или анализа. Например, при сортировке имён по алфавиту символ [ü] можно разложить на [u], за которым следует несамостоятельный знак [¨]. После такой декомпозиции алгоритму проще работать с последовательностью символов. Это позволяет упростить сортировку в языках, где модификаторы символов не влияют на алфавитный порядок. Стандарт Юникод устанавливает порядок декомпозиции для всех составных символов. Он также определяет формы нормализации для обеспечения уникальных представлений символов.

Мифы о Юникоде


Из слайдов презентации Марка Дэвиса «Мифы Юникода».

  • Юникод — это просто 16-битный код. — Некоторые ошибочно полагают, что Юникод — это просто 16-битный код, в котором каждый символ занимает 16 бит, и поэтому существует 65 536 возможных символов. На самом деле это не совсем так. Это самый распространённый миф о Юникоде, так что если вы тоже так думали раньше, не расстраивайтесь.
  • Можно взять для своих нужд любую кодовую точку, которая не используется. — Нет. Когда-нибудь это место займёт другой символ. Вместо этого используйте плоскости для частного использования или области без символов в каждой плоскости, где по стандарту не будет никаких символов.
  • Каждая кодовая точка Юникода представляет символ. — Нет. Есть много точек без символов (FFFE, FFFF, 1FFFE и др.) Кроме того, суррогатные кодовые точки, приватные и неиспользуемые кодовые точки, а также управляющие/форматирующие «символы» (RLM, ZWNJ и др.)
  • В Юникоде заканчивается место. — Если бы оно заполнялось линейно, то закончилось бы в 2140 году. Но место не заполняется линейно. Планы на будущее см. здесь.
  • Все знаки сопоставляются один к одному. — Нет. Возможны варианты:
    • Один ко многим: (β → SS)
    • С учётом контекста: (…Σ ←→ …ς и в то же время …ΣΤ… ←→ …στ…)
    • С учётом локали: (I ←→ ı и в то же время İ ←→ i)


Прикладные кодировки Юникода


Исходный код


04ca960278c9925a080f2870b00f5f0d.png


Совместный доступ к документу может быстро превратить редактирование в письменную рэп-битву, ведущуюся все более запутанной расстановкой управляющих от U+202a до U+202e

Специальные символы


Консорциум Unicode опубликовал диаграмму общей пунктуации, где можете найти более подробную информацию.
Подожди… что я только что прочитал?

Идентификаторы переменных могут включать пробелы!


U+3164 Заполнитель хангыль отображается в виде широкого пробела. Если символ явно не поддерживается в рендеринге, то отображается как полностью невидимый (и не занимает место, т. е. «нулевой ширины»). Это означает, что вы никогда не увидите уродливый символ замены символов (�).

Я пока не уверен, почему U+3164 указано вести себя таким образом. Интересно, что U+3164 был добавлен в Юникод в версии 1.1 (1993) — так что у специалистов Консорциума было много времени, чтобы его продумать. Во всяком случае, вот несколько примеров.

> var ᅟ = 'foo';
undefined
> ᅟ
'foo'


> var ㅤ= alert;
undefined
> var foo = 'bar'
undefined
> if ( foo ===ㅤ`baz` ){} 	// alert
undefined


> var varㅤfooㅤ\u{A60C}ㅤπ = 'bar';
undefined
> varㅤfooㅤꘌㅤπ
'bar'


**Примечание:** я тестировал рендеринг U+3164 на Ubuntu и OS X со следующими параметрами: `node`, `php`, `ruby`, `python3.5`, `scala`, `vim`, `cat`, `chrome`+`github gist'. Atom — единственная система, которая терпит неудачу, (некорректно) отображая пустые поля. Мне ещё предстоит проверить код в Emacs и Sublime. Насколько я понимаю, Консорциум Юникод не будет переназначать или переименовывать символы или кодовые точки, но его можно убедить изменить свойства символов, таких как ID_Start и ID_Continue.

Модификаторы


Объединитель нулевой ширины (ZWJ) является непечатным символом в компьютерном наборе некоторых сложных шрифтов, таких как арабский или любой индийский шрифт. При помещении между двумя символами, которые в противном случае не были бы связаны, ZWJ заставляет их печататься в объединённой форме.

Разъединитель нулевой ширины (ZWNJ) — это непечатный символ в компьютерных наборах письменностей с лигатурами. При размещении между двумя символами, которые в противном случае были бы соединены в лигатуру, ZWNJ заставляет их печататься в их окончательной и первоначальной формах, соответственно. Действует как пробел, но используется в том случае, когда желательно удерживать слова рядом друг с другом или соединить слово с его морфемой.

> 'a'
 "a"

> 'a\u{0308}'
 "ä"

> 'a\u{20DE}\u{0308}'
 "a⃞̈"

> 'a\u{20DE}\u{0308}\u{20DD}'
 "a⃞̈⃝"

// Modifying Invisible Characters
> '\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}'
 "‎‎‎‎‎‎‎‎‎‎"

> '\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}\u{200E}'.length
 10


Коллизии преобразований в верхнем регистре


Коллизии преобразований в нижнем регистре


  • Длина строки обычно определяется по количеству кодовых точек. Это означает, что суррогатные пары будут считаться двумя символами. На символ может быть наложено нескольких диакритических знаков: a + ̈ == ̈a. Это увеличивает длину строки, производя только один символ.
  • Аналогично, обращение строки часто становится нетривиальной задачей. Опять же, суррогатные пары и диакритические знаки следует обращать вместе. ES Reverser предлагает довольно хорошее решение.
  • Сопоставления верхнего и нижнего регистра не всегда совпадают. Они могут выражаться и такими отношениями:
    • Один ко многим: (ß → SS)
    • С учётом контекста: (…Σ ←→ …ς и …ΣΤ… ←→ …στ…)
    • С учётом локали: (I ←→ ı и İ ←→ i)

    Сопоставления одного ко многим


    Большинство нижеприведенных символов выражают свои сопоставления «один ко многим» в верхнем регистре, а другие в нижнем. В принципе, список можно разделить на две части.
    • PhantomScript — : ghost: : flashlight: Выполнение невидимого JavaScript и социальная инженерия
    • ESReverser — Обращение строка на JavaScript с учётом Юникода.
    • mimic — Некорректное использование Юникода
    • python-ftfy — Пытается создать максимальную корректное и цельное представление текста, поступившего в Юникоде.
    • vim-troll-stopper — Защита вашего кода от юникод-троллей.

    Многообразие


    Консорциум Unicode приложил огромные усилия для лучшего отражения человеческого многообразия (diversity), включая культурные практики. Вот отчёт Консорциума о многообразии.

    Теперь доступны эмодзи для разных гендерных ситуаций, включая однополые семьи, держащиеся руки и поцелуи. Последний функционал — это составные последовательности эмодзи. Основные примеры:


    Кроме того, эмодзи теперь поддерживают модификаторы цвета кожи.
    В Юникоде версии 8.0 (середина 2015 года) появилось пять символов-модификаторов символов для оттенков человеческой кожи. Эти символы основаны на шести оттенках по шкале Фицпатрика, признанного стандарта в дерматологии (в интернете много примеров этой шкалы, таких как FitzpatrickSkinType.pdf). Точные оттенки зависят от реализации.

    Отчёт Консорциума Unicode о многообразии


    Просто выбирайте нужный эмодзи, указав один из модификаторов цвета кожи \u{1F466}\u{1F3FE}.

    53dca3202f4e4d053120c0d79ea6a16e.png

    a8ae745f1751956af32cd39410d4bf95.png
     → 
    eafd1bc08af918072b48cc859ea787ba.png

    4731e87aa04f6e57112ea0e898bf5b9e.png


    Примеры на JavaScript (ES6)

    Обычно символы, обозначенные свойством ID_START, можно ставить в начале названия переменной. Символы, обозначенные свойством ID_CONTINUE, можно ставить после первого символа в имени переменной.

    // How convenient!
    var π = Math.PI;
    
    // Sometimes, you just have to use the Bad Parts of JavaScript:
    var ಠ_ಠ = eval;
    
    // Code, Y U NO WORK?!
    var ლ_ಠ益ಠ_ლ = 42;
    
    // How about a JavaScript library for functional programming?
    var λ = function() {};
    
    // Obfuscate boring variable names for great justice
    var \u006C\u006F\u006C\u0077\u0061\u0074 = 'heh';
    
    // …or just make up random ones
    var Ꙭൽↈⴱ = 'huh';
    
    // While perfectly valid, this doesn’t work in most browsers:
    var foo\u200Cbar = 42;
    
    // This is *not* a bitwise left shift (`<<`):
    var 〱〱 = 2;
    // This is, though:
    〱〱 << 〱〱; // 8
    
    // Give yourself a discount:
    var price_9̶9̶_89 = 'cheap';
    
    // Fun with Roman numerals
    var Ⅳ = 4;
    var Ⅴ = 5;
    Ⅳ + Ⅴ; // 9
    
    // Cthulhu was here
    var Hͫ̆̒̐ͣ̊̄ͯ͗͏̵̗̻̰̠̬͝ͅE̴̷̬͎̱̘͇͍̾ͦ͊͒͊̓̓̐_̫̠̱̩̭̤͈̑̎̋ͮͩ̒͑̾͋͘Ç̳͕̯̭̱̲̣̠̜͋̍O̴̦̗̯̹̼ͭ̐ͨ̊̈͘͠M̶̝̠̭̭̤̻͓͑̓̊ͣͤ̎͟͠E̢̞̮̹͍̞̳̣ͣͪ͐̈T̡̯̳̭̜̠͕͌̈́̽̿ͤ̿̅̑Ḧ̱̱̺̰̳̹̘̰́̏ͪ̂̽͂̀͠ = 'Zalgo';

    А вот некоторые юникодовские классы CSS от Дэвида Уолша.
    
    
    
    
    
    You do not have access to this page.
    Your changes have been saved successfully!
    .ಠ_ಠ {
    	border: 1px solid #f00;
    }
    
    . {
    	background: lightgreen;
    }

    Скрипт рекурсивного переименования тегов HTML


    Если вы хотите переименовать все свои HTML-теги в нечто невидимое, вот скрипт, который вам нужен.

    Только обратите внимание, что HTML поддерживает не все символы Юникода.

    // U+1160 HANGUL JUNGSEONG FILLER
    transformAllTags('ᅠ');
    
    // An actual HTML element node designed to look like a comment node, using the U+01C3 LATIN LETTER RETROFLEX CLICK 
    //	<ǃ-- name="viewport" content="width=device-width">
    transformAllTags('ǃ--');
    
    // or even <ᅠ⃝
    transformAllTags('\u{1160}\u{20dd}');
    
    // and for a bonus, all existing tag names will have each character ensquared. h⃞t⃞m⃞l⃞
    transformAllTags();
    
    
    function transformAllTags (newName){
       // querySelectorAll doesn't actually return an array.
       Array.from(document.querySelectorAll('*'))
         .forEach(function(x){
             transformTag(x, newName);
       });
    }
    
    function wonky(str){
      return str.split('').join('\u{20de}') + '\u{20de}';
    }
    
    function transformTag(tagIdOrElem, tagType){
        var elem = (tagIdOrElem instanceof HTMLElement) ? tagIdOrElem : document.getElementById(tagIdOrElem);
        if(!elem || !(elem instanceof HTMLElement))return;
        var children = elem.childNodes;
        var parent = elem.parentNode;
        var newNode = document.createElement(tagType||wonky(elem.tagName));
        for(var a=0;a

    Вот что он поддерживает:
    function testBegin(str){
     try{
        eval(`document.createElement( '${str}' );`)
        return true;
     }
     catch(e){ return false; }
    }
    
    function testContinue(str){
     try{
        eval(`document.createElement( 'a${str}' );`)
        return true;
     }
     catch(e){ return false; }
    }

    А вот некоторые результаты:
    // Test if dashes can start an HTML Tag
    > testBegin('-')
    < false
    
    > testContinue('-')
    < true
    
    > testBegin('ᅠ-')	// Prepend dash with U+1160 HANGUL JUNGSEONG FILLER
    < true

    Ни один шрифт TrueType или OpenType не способен охватить все символы UTF-8, поскольку есть жёсткое ограничение на 65 535 символов в шрифте. Если у нас более 1,1 миллиона глифов UTF-8, то для полного покрытия придётся делать семейство шрифтов.

    Карта основной многоязычной плоскости


    Каждое нумерованное поле представляет собой 256 кодовых точек.

    64c1b8b22d1a20bcde65bcca2683f5b0.png

    Китайские, японские и корейские (ККЯ) письменности объединены одним цветом как символы ККЯ (CJK). В процессе, который называется унификацией Хань, распознаются общие символы и составляется список «унифицированных идеограмм ККЯ».

    Блоки Юникода


    Стандарт Юникод объединяет группы символов в блоки. Вот полный список блоков по всем 17-ти плоскостям.

    Принципы Стандарта Юникод


    Стандарт Юникод устанавливает следующие фундаментальные принципы:
    • Универсальность — каждую когда-либо используемую письменную система следует уважать и представить в стандарте.
    • Логический порядок — в двунаправленном тексте символы хранятся в логическом порядке, а не в соответствии с представлением.
    • Эффективность — документация должна быть эффективной и полной.
    • Унификация — если разные культуры или языки используют один и тот же символ, он должен быть включен только один раз. Это ведёт к следующему пункту.
    • Символы, а не глифы — кодируются только символы, а не глифы. В двух словах, глифы являются фактической графической репрезентацией.
    • Динамическая композиция — новые символы могут быть составлены из других, уже стандартизированных символов. Например, символ [Ä] может состоять из символа [A] и символа диерезиса [¨].
    • Семантика — включённые символы должны быть чётко определены и отличаться от других.
    • Стабильность — однажды определённые, символы никогда не будут удалены, а их кодовые точки никогда не будут переназначены. В случае ошибки кодовая точка считается устаревшей.
    • Обычный текст — символы в стандарте являются текстом, они никогда не могут быть разметкой или метасимволами.
    • Конвертируемость — любая другая используемая кодировка должна иметь возможность быть представленной в терминах кодировки Юникода.

    Источник: описание принципов c codepoints.net.

© Habrahabr.ru