Если вы настаиваете на обратном порядке байтов (по какой-то странной причине), вы все равно можете просто отсканировать первый бит, равный 1, разделить на 8 и +1, чтобы получить количество байтов.
GetReversedShiftedUtf8BytesCount:
; eax = UTF8 code in reversed order, by from LSB
; 'É' (c3 89) => eax = 0x0000c389
bsr ecx,eax
cmovz ecx,eax ; needed only for eax = 0
; ^ if eax is never 0 on input, this "cmovz" can be removed
shr ecx,3
inc ecx
ret
Когда вы помещаете первый байт символа в MSB, он будет производить количество битов 15, 23 или 31 для многобайтовых символов, для 7b ASCII что-либо от 0 до 6 будет производиться bsr
. «div 8» исправит их все, в любом случае, ему все равно.
Эта процедура должна фактически работать также с действительными нормальными кодами UTF8.
Для неверного кода UTF8, заканчивающегося нулевым байтом, будет возвращено неправильное количество байтов (без нулевых).
Конечно, как и всегда, также возможно решение LUT:
movzx ecx,al
shr ecx,3
movzx ecx,byte [utf8lengthLUT + ecx] ; +rcx for 64b
; ecx = number of bytes or 0 for invalid leading byte value
...
utf8lengthLUT: ; 32B look-up table for upper 5b of 1st byte
db 1, 1, 1, 1, 1, 1, 1, 1 ; 00000 - 00111 ; single byte
db 1, 1, 1, 1, 1, 1, 1, 1 ; 01000 - 01111 ; single byte
db 0, 0, 0, 0, 0, 0, 0, 0 ; 10000 - 10111 ; not valid leading byte
db 2, 2, 2, 2 ; 11000 - 11011 ; two bytes code point
db 3, 3 ; 11100 - 11101 ; three bytes code point
db 4 ; 11110 ; four bytes code point
db 0 ; 11111 ; not valid leading byte
Я не отлаживал его, просто пытался перевести с помощью nasm для проверки синтаксиса. И я не профилировал его, конечно. :) Глядя на краткость этого варианта bsr
, я сомневаюсь, что он будет серьезно быстрее даже на процессорах, где bsr
вредит.
Но этот обрабатывает недопустимые коды операций UTF8 по-другому, вместо того, чтобы обнаруживать ненулевой MSB и возвращать его число + 1 (не чувствительно к содержимому начального байта), он правильно декодирует информацию о начальном байте и возвращает 0, когда начальные биты неверны. Но правильные начальные биты с неправильным 2-м+ байтом (например, c3 00
) все равно будут возвращать 2
, тогда как первый вариант в таком случае возвращает 1
.
(можно использовать только 16-битную таблицу LUT, если вас не волнует недопустимая информация о начальных 11111
байтах, и вы примете это как 4-байтовую кодовую точку)
Кстати, есть некоторые библиотеки i18n (с открытым исходным кодом), выполняющие все эти действия, такие как проверка входных данных utf8, исправление неверных, подсчет символов и т. д. Некоторые из них существуют уже более десяти лет... и все еще получают ошибки. отчеты и исправления. Что является своего рода тонким намеком на то, как сложно правильно написать этот материал (не подвергая приложение какой-либо уязвимости входных данных). :)
(плюс учитывая, сколько (исправлений) правок получили эти два ответа... :))
И еще один оффтопный совет: если вы когда-нибудь попытаетесь написать что-то на PHP, то должны обрабатывать входные данные UTF8 (которые не из доверенного источника, но даже из доверенного источника), особенно если эти входные данные из ответа GET/POST. .. только не по своему усмотрению. Никогда. Получите некоторую основу для этого. :)
person
Ped7g
schedule
21.12.2016
eax
, можете привести примеры? Я ожидал что-то вроде0x89c389c3
вместоÉÉ
(один символÉ
с началом следующего символа, который также являетсяÉ
и помещается в оставшиеся два байтаeax
). Что читает ваш код в таком случае? (текст имеет байтыc3 89 c3 89
) Если бы вы предоставили примеры для каждой длины, было бы лучше проверить любые предложения по ним. (плюс то, как сильно вы стеснены в запасных регистрах) - person Ped7g   schedule 21.12.2016É
, за которым следует второйÉ
). Итак, для одного (1) персонажа:rax = 0x000000000000c3a1
- person Frank C.   schedule 21.12.2016c3a1
(á
) опечатка на вашей стороне, или я все еще не понимаю, как работают ваши преобразования ценности? Если вы идете по символу, что-то уже проанализировало этот символ. Кстати, почему что-то не обеспечивает также длину? Тогда вы анализируете его дважды. Если вы не возражаете, то почему вы беспокоитесь о производительности второго синтаксического анализа, если вы не возражаете против производительности? Я немного смущен этим. - person Ped7g   schedule 21.12.2016rax = 0x000000000000c389
- person Frank C.   schedule 21.12.2016