std.utf

Переместиться к: byChar · byCodeUnit · byDchar · byUTF · byWchar · codeLength · count · decode · decodeFront · encode · isValidDchar · replacementDchar · stride · strideBack · toUCSindex · toUTF16 · toUTF16z · toUTF32 · toUTF8 · toUTFindex · toUTFz · UseReplacementDchar · UTFException · validate

Кодирование и декодирование строк в кодировках UTF-8, UTF-16 и UTF-32.
Поддерживаются UTF-символы в пределах '\u0000' <= код символа <= '\U0010FFFF'.
Замечание по поводу перевода Unicode-терминологии: "code unit" я перевожу как "кодовый блок", "code point" я перевожу как "кодовая точка". Возможно, это неверно, в википедии "code point" переведено как "кодовая позиция". Тем не менее, оставлю свой вариант, т.к. уже много где его применял – прим.пер.
Смотрите также:
Wikipedia
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335
Лицензия:
Boost License 1.0.
Авторы:
Walter Bright and Jonathan M Davis

Исходный код: std/utf.d

class UTFException: object.Exception;
Исключение, вызываемое ошибками в функциях модуля std.utf.
pure nothrow @nogc @safe bool isValidDchar(dchar c);
Проверяет, является ли данная кодовая точка Юникода действительной.
Параметры:
dchar c проверяемая кодовая точка
Возвращает:
true, если c является действительной кодовой точкой Юникода

Замечание: '\uFFFE' и '\uFFFF' функцией isValidDchar считаются действительными, поскольку они разрешены для внутреннего использования приложением, но они не разрешены для обмена по стандарту Юникода.

uint stride(S)(auto ref S str, size_t index)
if (is(S : const(char[])) || isRandomAccessRange!S && is(Unqual!(ElementType!S) == char));

uint stride(S)(auto ref S str)
if (is(S : const(char[])) || isInputRange!S && is(Unqual!(ElementType!S) == char));

uint stride(S)(auto ref S str, size_t index)
if (is(S : const(wchar[])) || isRandomAccessRange!S && is(Unqual!(ElementType!S) == wchar));

pure @safe uint stride(S)(auto ref S str)
if (is(S : const(wchar[])));

uint stride(S)(auto ref S str)
if (isInputRange!S && is(Unqual!(ElementType!S) == wchar));

uint stride(S)(auto ref S str, size_t index = 0)
if (is(S : const(dchar[])) || isInputRange!S && is(Unqual!(ElementEncodingType!S) == dchar));
Вычисляет длину UTF-последовательности, начиная с index в str.
Параметры:
S str Входной диапазон из кодовых блоков UTF. Должен быть диапазоном с произвольным доступом, если передан index
size_t index начальный индекс UTF-последовательности (по-умолчанию: 0)
Возвращает:
Количество кодовых блоков в UTF-последовательности. Для UTF-8 это значение от 1 до 4 (согласно RFC 3629, section 3). Для UTF-16 это либо 1, либо 2. Для UTF-32 это всегда 1.
Исключения:
Может вызвать исключение UTFException, если str[index] не является началом действительной UTF-последовательности.

Замечание: stride будет анализировать только первый элемент str[index]. Она не будет полностью проверять достоверность UTF-последовательности и даже не будет проверять наличие последовательности: фактически не гарантируется, что index + stride(str, index) <= str.length.

uint strideBack(S)(auto ref S str, size_t index)
if (is(S : const(char[])) || isRandomAccessRange!S && is(Unqual!(ElementType!S) == char));

uint strideBack(S)(auto ref S str)
if (is(S : const(char[])) || isRandomAccessRange!S && hasLength!S && is(Unqual!(ElementType!S) == char));

uint strideBack(S)(auto ref S str)
if (isBidirectionalRange!S && is(Unqual!(ElementType!S) == char) && !isRandomAccessRange!S);

uint strideBack(S)(auto ref S str, size_t index)
if (is(S : const(wchar[])) || isRandomAccessRange!S && is(Unqual!(ElementType!S) == wchar));

uint strideBack(S)(auto ref S str)
if (is(S : const(wchar[])) || isBidirectionalRange!S && is(Unqual!(ElementType!S) == wchar));

uint strideBack(S)(auto ref S str, size_t index)
if (isRandomAccessRange!S && is(Unqual!(ElementEncodingType!S) == dchar));

uint strideBack(S)(auto ref S str)
if (isBidirectionalRange!S && is(Unqual!(ElementEncodingType!S) == dchar));
Вычисляет длину UTF-последовательности последнего кодового блока перед index в str.
Параметры:
S str Двунаправленный диапазон кодовых блоков UTF. Должен быть с произвольным доступом, если передан index
size_t index Индекс, следующий после конца UTF-последовательности (по-умолчанию str.length)
Возвращает:
Количество кодовых блоков в UTF-последовательности. Для UTF-8 это значение от 1 до 4 (согласно RFC 3629, section 3). Для UTF-16 это либо 1, либо 2. Для UTF-32 это всегда 1.
Исключения:
Может вызывать исключение UTFException, если str[index] не находится после окончания допустимой UTF-последовательности.

Замечание: strideBack будет анализировать только элемент str[index - 1]. Она не будет полностью проверять действительность UTF-последовательности и даже не проверит наличие последовательности: фактически не гарантируется, что strideBack(str, index) <= index.

pure @safe size_t toUCSindex(C)(const(C)[] str, size_t index)
if (isSomeChar!C);
Принимая индекс index в строке str и предполагая, что index находится в начале UTF-последовательности, toUCSindex определяет количество UCS-символов до индекса. Таким образом, index является индексом кодового блока в начале кодовой точки, а возвращаемое значение – количество кодовых точек в строке, в которой находится эта кодовая точка.
Примеры:
assert(toUCSindex(`hello world`, 7) == 7);
assert(toUCSindex(`hello world`w, 7) == 7);
assert(toUCSindex(`hello world`d, 7) == 7);

assert(toUCSindex(`Ma Chérie`, 7) == 6);
assert(toUCSindex(`Ma Chérie`w, 7) == 7);
assert(toUCSindex(`Ma Chérie`d, 7) == 7);

assert(toUCSindex(`さいごの果実 / ミツバチと科学者`, 9) == 3);
assert(toUCSindex(`さいごの果実 / ミツバチと科学者`w, 9) == 9);
assert(toUCSindex(`さいごの果実 / ミツバチと科学者`d, 9) == 9);
pure @safe size_t toUTFindex(C)(const(C)[] str, size_t n)
if (isSomeChar!C);
Принимая n в качестве UCS-индекса в str, возвращает UTF-индекс. Таким образом, n – это номер кодовой точки в строке, а возвращается индекс массива кодовых блоков.
Примеры:
assert(toUTFindex(`hello world`, 7) == 7);
assert(toUTFindex(`hello world`w, 7) == 7);
assert(toUTFindex(`hello world`d, 7) == 7);

assert(toUTFindex(`Ma Chérie`, 6) == 7);
assert(toUTFindex(`Ma Chérie`w, 7) == 7);
assert(toUTFindex(`Ma Chérie`d, 7) == 7);

assert(toUTFindex(`さいごの果実 / ミツバチと科学者`, 3) == 9);
assert(toUTFindex(`さいごの果実 / ミツバチと科学者`w, 9) == 9);
assert(toUTFindex(`さいごの果実 / ミツバチと科学者`d, 9) == 9);
alias UseReplacementDchar = std.typecons.Flag!"useReplacementDchar".Flag;
Whether or not to replace invalid UTF with replacementDchar
dchar decode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar, S)(auto ref S str, ref size_t index)
if (!isSomeString!S && isRandomAccessRange!S && hasSlicing!S && hasLength!S && isSomeChar!(ElementType!S));
Декодирует и возвращает кодовую точку, которая начинается с str[index]. Значение index увеличивается до следующего после декодированной кодовой точки. Если кодовая точка не является корректной, генерируется исключение UTFException, а index остаётся неизменным.
decode будет работать только со строками и диапазонами кодовых блоков с произвольным доступом с определённой длиной (length) и поддержкой срезов, в то время как decodeFront будет работать с любым входным диапазоном кодовых блоков.
Параметры:
useReplacementDchar при недопустимом UTF возвращать replacementDchar вместо вызова исключения
S str входная строка или индексируемый диапазон
size_t index Начальный индекс в s[]; Увеличивается на количество пройденных кодовых блоков
Возвращает:
декодированный символ
Исключения:
UTFException, если str[index] не является началом допустимой UTF-последовательности и useReplacementDchar равно No.useReplacementDchar
dchar decodeFront(UseReplacementDchar useReplacementDchar = No.useReplacementDchar, S)(ref S str, out size_t numCodeUnits)
if (!isSomeString!S && isInputRange!S && isSomeChar!(ElementType!S));

dchar decodeFront(UseReplacementDchar useReplacementDchar = No.useReplacementDchar, S)(ref S str)
if (isInputRange!S && isSomeChar!(ElementType!S));
decodeFront – это вариант функции decode, который декодирует именно первую кодовую точку. В отличие от decode, decodeFront принимает входной диапазон кодовых блоков любого типа (а не только строку или диапазон с произвольным доступом). Он также принимает диапазон по ссылке (с помошью ref) и выталкивает элементы, которые декодирует. Если передается параметр numCodeUnits, он получает значение количества кодовых блоков, которые были в декодированной кодовой точке.
Параметры:
useReplacementDchar при недопустимом UTF возвращать replacementDchar вместо вызова исключения
S str входная строка или входной диапазон
size_t numCodeUnits установить количество обработанных кодовых блоков
Возвращает:
декодированный символ
Исключения:
UTFException, если str.front не является началом действительной UTF-последовательности. Если вызвано исключение, то нет никакой гарантии относительно количества вытолкнутых кодовых блоков, поскольку оно зависит от типа используемого диапазона и количества кодовых блоков, которые могли быть вытолкнуты, прежде чем была определена недействительность кодовой точки.

Переместиться к: 2

pure @safe size_t encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(ref char[4] buf, dchar c);

pure @safe size_t encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(ref wchar[2] buf, dchar c);

pure @safe size_t encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(ref dchar[1] buf, dchar c);
Кодирует c в статический массив buf и возвращает фактическую длину закодированного символа (число от 1 до 4 для буферов char[4] и число от 1 до 2 для буферов wchar[2]).
Исключения:
UTFException, если c не является допустимой кодовой точкой UTF.
pure @safe void encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(ref char[] str, dchar c);

pure @safe void encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(ref wchar[] str, dchar c);

pure @safe void encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(ref dchar[] str, dchar c);
Кодирует c в кодировку str и присоединяет ее к str.
Исключения:
UTFException, если c не является допустимой кодовой точкой UTF.

Переместиться к: 2

pure nothrow @nogc @safe ubyte codeLength(C)(dchar c)
if (isSomeChar!C);
Возвращает количество кодовых блоков, которые необходимы для кодирования кодовой точки c, где C – тип символа, используемого для его кодирования.
Примеры:
assert(codeLength!char('a') == 1);
assert(codeLength!wchar('a') == 1);
assert(codeLength!dchar('a') == 1);

assert(codeLength!char('\U0010FFFF') == 4);
assert(codeLength!wchar('\U0010FFFF') == 2);
assert(codeLength!dchar('\U0010FFFF') == 1);
size_t codeLength(C, InputRange)(InputRange input)
if (isInputRange!InputRange && is(ElementType!InputRange : dchar));
Возвращает количество кодовых блоков, которые необходимы для кодирования input в строке, тип символа которой равен C. Это особенно полезно при отрезании одной строки до длины другой, а два типа строк используют разные типы символов.
Примеры:
import std.conv : to;
assert(codeLength!char("hello world") ==
       to!string("hello world").length);
assert(codeLength!wchar("hello world") ==
       to!wstring("hello world").length);
assert(codeLength!dchar("hello world") ==
       to!dstring("hello world").length);

assert(codeLength!char(`プログラミング`) ==
       to!string(`プログラミング`).length);
assert(codeLength!wchar(`プログラミング`) ==
       to!wstring(`プログラミング`).length);
assert(codeLength!dchar(`プログラミング`) ==
       to!dstring(`プログラミング`).length);

string haystack = `Être sans la verité, ça, ce ne serait pas bien.`;
wstring needle = `Être sans la verité`;
assert(haystack[codeLength!char(needle) .. $] ==
       `, ça, ce ne serait pas bien.`);
pure @safe void validate(S)(in S str)
if (isSomeString!S);
Проверяет, является ли строка str правильно сформированной для Юникода или нет.
Исключения:
UTFException, если str не является правильно сформированной.
string toUTF8(S)(S s)
if (isInputRange!S && isSomeChar!(ElementEncodingType!S));
Кодирует элементы s в UTF-8 и возвращает вновь выделенную строку элементов.
Параметры:
S s строка для кодирования
Возвращает:
Строку в кодировке UTF-8
Смотрите также:
Для ленивой, не выделяющей память версии этих функций см. byUTF.
Примеры:
import std.algorithm.comparison : equal;

// Символ ø представляется двумя кодовыми блоками UTF-8
assert("Hellø"w.toUTF8.equal(['H', 'e', 'l', 'l', 0xC3, 0xB8]));

// 𐐷 состоит из четырёх кодовых блоков в UTF-8
assert("𐐷"d.toUTF8.equal([0xF0, 0x90, 0x90, 0xB7]));
wstring toUTF16(S)(S s)
if (isInputRange!S && isSomeChar!(ElementEncodingType!S));
Кодирует элементы s в UTF-16 и возвращает новую, выделенную сборщиком мусора строку элементов типа wstring.
Параметры:
S s диапазон для кодирования
Возвращает:
Строку в кодировке UTF-16
Смотрите также:
Для ленивой, не выделяющей память версии этих функций см. byUTF.
Примеры:
import std.algorithm.comparison : equal;

// Эти графемы представляются двумя кодовыми блоками в UTF-16 и одним в UTF-32
assert("𤭢"d.length == 1);
assert("𐐷"d.length == 1);

assert("𤭢"d.toUTF16.equal([0xD852, 0xDF62]));
assert("𐐷"d.toUTF16.equal([0xD801, 0xDC37]));
pure @safe dstring toUTF32(scope const char[] s);

pure @safe dstring toUTF32(scope const wchar[] s);

pure @safe dstring toUTF32(scope const dchar[] s);
Кодирует строку s в кодировку UTF-32 и возвращает закодированную строку.
template toUTFz(P)
Возвращает строку в стиле C с нулевым символом на конце, эквивалентную str. str не должна содержать внутри себя символы '\0', так как любая C-функция будет обрабатывать первый встреченный ей символ '\0' как конец строки. Если истинно str.empty, возвращается строка, содержащая только '\0'.
toUTFz принимает строку любого типа и шаблонизируется по типу указателя символа, в который вы хотите выполнить преобразование. Это позволяет, по возможности, избежать выделения новой строки, но существует приличная вероятность, что выделять новую строку ей придется – особенно при работе с типами символов, отличными от char.
Предупреждение 1: Если результат toUTFz равен str.ptr, то если что-то изменит символ, который находится после конца str (т.е. после символа окончания строки '\0'), то строка больше не будет заканчиваться нулевым символом. Наиболее вероятными сценариями для этого являются, если вы добавите другую строку к str и при этом не произойдёт перераспределение памяти, или когда str является срезом массива большего размера, и вы измените символ в большем массиве, после последнего символа str. Другой случай, когда это может произойти, если у вас был изменяемый массив символов сразу после str в памяти (например, если они являются переменными-членами в определённом пользователем типе с объявлением сразу один после другого), и этот массив символов случайно начинается с '\0'. Такие сценарии никогда не произойдут, если вы сразу же используете строку, оканчивающуюся нулевым символом, после вызова toUTFz, а C-функция, использующая ее, не будет удерживать ссылку на неё. Кроме того, они вряд ли произойдут, даже если вы сохраните строку, оканчивающуюся нулевым символом, (приведённые выше случаи были бы в числе немногих примеров того, где это могло произойти). Однако, если вы сохраняете строку, оканчивающуюся нулевым символом, и хотите быть абсолютно уверены, что строка останется такой, просто добавьте '\0' к строке и используйте её свойство ptr вместо вызова toUTFz.
Предупреждение 2: Если вы передаёте символьный указатель в C-функцию, а C-функция сохраняет его по какой-либо причине, убедитесь, что вы удерживаете ссылку на неё в своем D-коде. В противном случае строка может исчезнуть во время цикла сбора мусора и вызвать неприятную ошибку, когда код на C попытается её использовать.
Примеры:
auto p1 = toUTFz!(char*)("hello world");
auto p2 = toUTFz!(const(char)*)("hello world");
auto p3 = toUTFz!(immutable(char)*)("hello world");
auto p4 = toUTFz!(char*)("hello world"d);
auto p5 = toUTFz!(const(wchar)*)("hello world");
auto p6 = toUTFz!(immutable(dchar)*)("hello world"w);
pure @safe const(wchar)* toUTF16z(C)(const(C)[] str)
if (isSomeChar!C);
toUTF16z – это удобная функция, вызывающая toUTFz!(const(wchar)*).
Кодирует строку s в UTF-16 и возвращает закодированную строку. toUTF16z подходит для вызова 'W'-функций в Win32 API, которые принимают аргумент типа LPWSTR или LPCWSTR.
pure nothrow @nogc @trusted size_t count(C)(const(C)[] str)
if (isSomeChar!C);
Возвращает общее число кодовых точек, закодированных в str.

Заменяет: Эта функция заменяет toUCSindex.

Стандарты:
Unicode 5.0, ASCII, ISO-8859-1, WINDOWS-1252
Исключения:
UTFException , если str не является корректной.
enum dchar replacementDchar;
Вставляется вместо недействительных UTF-последовательностей.
auto byCodeUnit(R)(R r)
if (isAutodecodableString!R);

ref auto byCodeUnit(R)(R r)
if (!isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R));
Итерирует диапазон символов типа char, wchar или dchar по кодовым блокам.
Применяется с целью обойти специальное декодирование, которое std.range.primitives.front выполняет для массивов символов. В результате использование диапазонов с помощью функции byCodeUnit не будет выбрасывать исключений, в отличие от std.range.primitives.front, если она столкнётся с некорректными Unicode-последовательностями.
Кодовый блок является строительным блоком для UTF-кодировок. Как правило, отдельный кодовый блока не представляет того, что воспринимается как полноценный символ (или grapheme cluster в терминологии Unicode). Многие символы кодируются несколькими кодовыми блоками. Например, кодовые блоки UTF-8 для символа ø – это 0xC3 0xB8. Это означает, что отдельный элемент byCodeUnit часто сам по себе не формирует символ. Попытки рассматривать его как единое целое во время итерации по результирующему диапазону дадут бессмысленные результаты.
Параметры:
R r входной диапазон символов или массив символов
Возвращает:
Если r не является автоматически декодируемой строкой, тогда возвращается r.
В противном случае, входной диапазон с длиной, если std.traits.isAggregateType возвращает true для R. Иначе возвращается конечный диапазон с произвольным доступом с поддержкой срезов.
Смотрите также:
Смотрите документацию модуля std.uni, чтобы получить информацию по терминологии Unicode.
Для итерирования диапазона по grapheme cluster (печатаемым символам), смотрите функцию std.uni.byGrapheme.
Примеры:
auto r = "Hello, World!".byCodeUnit();
static assert(hasLength!(typeof(r)));
static assert(hasSlicing!(typeof(r)));
static assert(isRandomAccessRange!(typeof(r)));
static assert(is(ElementType!(typeof(r)) == immutable char));

// в противовес диапазонным возможностям стандартных строк
auto s = "Hello, World!";
static assert(isBidirectionalRange!(typeof(r)));
static assert(is(ElementType!(typeof(s)) == dchar));

static assert(!isRandomAccessRange!(typeof(s)));
static assert(!hasSlicing!(typeof(s)));
static assert(!hasLength!(typeof(s)));
Примеры:
byCodeUnit не декодирует Unicode
string noel1 = "noe\u0308l"; // noël использует e + комбинируемое надстрочное двоеточие (умляут)
assert(noel1.byCodeUnit[2] != 'ë');
assert(noel1.byCodeUnit[2] == 'e');

string noel2 = "no\u00EBl"; // noël использует предварительно собранный символ ë
// Поскольку string - это UTF-8, кодовый блок по индексу 2 является только первым из 
// последовательности, которая кодирует 'ë' 
assert(noel2.byCodeUnit[2] != 'ë');
alias byChar = byUTF!char.byUTF(R)(R r) if (isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R));

alias byWchar = byUTF!wchar.byUTF(R)(R r) if (isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R));

alias byDchar = byUTF!dchar.byUTF(R)(R r) if (isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R));
Итерирует входной символьный диапазон по элементам char, wchar или dchar. Эти псевдонимы просто перенаправляются byUTF с соответствующим аргументом C.
Параметры:
R r входной диапазон символов или массив символов
template byUTF(C) if (isSomeChar!C)
Итерирует входной символьный диапазон символом типа C, кодируя элементы диапазона.
UTF-последовательности, которые нельзя преобразовать в указанную кодировку, заменяются на U+FFFD в соответсвии с «5.22 Best Practice for U+FFFD Substitution» стандарта Unicode. Следовательно, byUTF не является симметричным. Этот алгоритм ленив и не выделяет память. Квалификаторы @nogc, pure, nothrow и @safe выводятся из параметра r.
Параметры:
C char, wchar, или dchar
r входной диапазон символов или массив символов
Возвращает:
Лидирующий диапазон, если r – это диапазон, не являющийся автоматически декодируемым, как это определяет функция std.traits.isAutodecodableString, и если базовый диапазон также является лидирующим диапазоном.
Или, если r – это диапазон, являющийся автоматически декодируемым, и выполняется условие is(ElementEncodingType!typeof(r) == C), тогда диапазон передается в функцию byCodeUnit.
В противном случае – входной диапазон символов.
Примеры:
import std.algorithm.comparison : equal;

// hellö является диапазоном элементов типа `char`, который представляет UTF-8
"hell\u00F6".byUTF!char().equal(['h', 'e', 'l', 'l', 0xC3, 0xB6]);

// `wchar` способен удерживать ö в одном элементе (кодовом блоке UTF-16)
"hell\u00F6".byUTF!wchar().equal(['h', 'e', 'l', 'l', 'ö']);

// 𐐷 состоит из четырёх кодовых блоков в UTF-8, двух в UTF-16 и одного в UTF-32
"𐐷".byUTF!char().equal([0xF0, 0x90, 0x90, 0xB7]);
"𐐷".byUTF!wchar().equal([0xD801, 0xDC37]);
"𐐷".byUTF!dchar().equal([0x00010437]);