Сначала давайте рассмотрим ваш "метод 55357" и почему он работает для многих символов эмодзи.
В Cocoa NSString
— это набор unichar
, а unichar
— это просто псевдоним типа для unsigned short
, который совпадает с UInt16
. Поскольку максимальное значение UInt16
равно 0xffff
, это исключает возможность размещения нескольких смайликов в одном unichar
, поскольку только два из шести основных блоков Unicode, используемых для смайликов, попадают в этот диапазон:
Эти блоки содержат 113 смайликов, а дополнительные 66 смайликов, которые можно представить как один unichar
, можно найти разбросанными по различным другим блокам. Однако эти 179 символов представляют лишь часть из 1126 базовых символов эмодзи, остальные должны быть представлены более чем одним unichar
.
Давайте проанализируем ваш код:
unichar unicodevalue = [text characterAtIndex:0];
Происходит то, что вы просто берете первые unichar
строки, и хотя это работает для ранее упомянутых 179 символов, оно распадается, когда вы сталкиваетесь с символом UTF-32, поскольку NSString
преобразует все в кодировку UTF-16. Преобразование работает путем замены значения UTF-32 на суррогатные пары. , что означает, что NSString
теперь содержит два unichar
.
И теперь мы переходим к тому, почему число 55357 или 0xd83d
используется для многих эмодзи: когда вы смотрите только на первое значение UTF-16 символа UTF-32, вы получаете старший суррогат, каждый из которых имеет диапазон 1024 младших суррогатов. Диапазон старшего суррогата 0xd83d
— от U+1F400 до U+1F7FF, который начинается в середине самого большого блока эмодзи, Разные символы и пиктограммы (U+1F300–U+1F5FF) и продолжается вплоть до Расширенные геометрические фигуры (U+1F780–U+1F7FF) — содержит в общей сложности 563 смайлика и 333 символа, не являющегося смайликом, в этом диапазоне.
Таким образом, впечатляющие 50% базовых символов смайликов имеют высокий суррогат 0xd83d
, но эти методы вывода по-прежнему оставляют необработанными 384 символа смайликов, а также дают ложные срабатывания как минимум для такого же количества.
Итак, как определить, является ли персонаж эмодзи или нет?
Недавно я ответил на вопрос, связанный с реализацией Swift, и если хотите, можете посмотреть, как обнаруживаются эмодзи. в этой структуре, которую я создал с целью замены стандартных эмодзи пользовательскими изображениями.
В любом случае, вы можете извлечь кодовую точку UTF-32 из символов, что мы и сделаем в соответствии с спецификация:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
// Get the UTF-16 representation of the text.
unsigned long length = text.length;
unichar buffer[length];
[text getCharacters:buffer];
// Initialize array to hold our UTF-32 values.
NSMutableArray *array = [[NSMutableArray alloc] init];
// Temporary stores for the UTF-32 and UTF-16 values.
UTF32Char utf32 = 0;
UTF16Char h16 = 0, l16 = 0;
for (int i = 0; i < length; i++) {
unichar surrogate = buffer[i];
// High surrogate.
if (0xd800 <= surrogate && surrogate <= 0xd83f) {
h16 = surrogate;
continue;
}
// Low surrogate.
else if (0xdc00 <= surrogate && surrogate <= 0xdfff) {
l16 = surrogate;
// Convert surrogate pair to UTF-32 encoding.
utf32 = ((h16 - 0xd800) << 10) + (l16 - 0xdc00) + 0x10000;
}
// Normal UTF-16.
else {
utf32 = surrogate;
}
// Add UTF-32 value to array.
[array addObject:[NSNumber numberWithUnsignedInteger:utf32]];
}
NSLog(@"%@ contains values:", text);
for (int i = 0; i < array.count; i++) {
UTF32Char character = (UTF32Char)[[array objectAtIndex:i] unsignedIntegerValue];
NSLog(@"\t- U+%x", character);
}
return YES;
}
Ввод «????» в UITextView
выводит это на консоль:
???? contains values:
- U+1f60e
Следуя этой логике, просто сравните значение character
с вашим источником данных кодовых точек смайликов, и вы точно узнаете, является ли персонаж смайликом или нет.
P.S.
Есть несколько «невидимых» символов, а именно селекторы вариантов и объединители нулевой ширины, с которыми тоже нужно работать, поэтому я рекомендую изучить те, чтобы узнать, как они себя ведут.
person
xoudini
schedule
07.12.2016