2014-06-17 2 views
1

Я работаю над приложением iOS с бэкэндром PHP + MySQL. В приложении есть раздел чата, который должен поддерживать emoji. Мои таблицы: utf8_unicode_ci. Если я не называю «set names utf8» в своих сценариях, то на самом деле он работает - все, что вводится в базе данных, возвращается клиентам, как и должно быть.MySQL, символы UTF-8 и Emoji

Проблема заключается в том, что это (если я правильно ее понимаю) неправильно хранит специальные символы в базе данных, и это прерывает сравнение строк (т.е., при сравнении строк не совпадает с i).

Однако, если я вызываю имена наборов utf8, внезапно символы emoji вставляются как куча вопросительных знаков.

Любые предложения по правильному обращению с этим? Благодаря!

ответ

1

Проблема заключается в том, что db имеет диакритическое нечувствительное сравнение. Другая проблема состоит из символов, • может быть выражена как один символ Юникода, либо два, образующие суррогатную пару. Существуют методы преобразования строки в предварительно сложенную или разложенную форму: precomposedStringWith * и decposedStringWith *.

Похоже, что MySQL поддерживает две формы unicode ucs2 (это более старая форма, которая была заменена utf16), которая представляет собой 16 бит на символ и utf8 до 3 байтов на символ. Плохая новость заключается в том, что ни одна из форм не будет поддерживать символы плоскости 1, которые требуют 17 бит. (главным образом эможи). Он похож на MySQL 5.5.3, а также поддерживает utf8mb4, utf16 и utf32 поддерживает BMP и дополнительные символы (читайте emoji). См. MySQL Unicode Character Sets.

Вот несколько кодов и результатов для демонстрации различных представлений байтов юникода.
Unicode - это 21-битная система кодирования.
UTF32 непосредственно представляет собой кодовые точки и наглядно демонстрирует разложенные суррогатные пары.
UTF8 и UTF16 требуют, чтобы один или несколько байтов представляли символ юникода.

NSLog(@"character: %@", @"Å"); 
NSLog(@"decomposedStringWithCanonicalMapping UTF8: %@", [[@"Å" decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF8StringEncoding]); 
NSLog(@"decomposedStringWithCanonicalMapping UTF16: %@", [[@"Å" decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF16BigEndianStringEncoding]); 
NSLog(@"decomposedStringWithCanonicalMapping UTF32: %@", [[@"Å" decomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF32BigEndianStringEncoding]); 

NSLog(@"precomposedStringWithCanonicalMapping UTF8: %@", [[@"Å" precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF8StringEncoding]); 
NSLog(@"precomposedStringWithCanonicalMapping UTF16: %@", [[@"Å" precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF16BigEndianStringEncoding]); 
NSLog(@"precomposedStringWithCanonicalMapping UTF32: %@", [[@"Å" precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF32BigEndianStringEncoding]); 

NSLog(@"character: %@", @""); 
NSLog(@"dataUsingEncoding UTF8: %@", [@"" dataUsingEncoding:NSUTF8StringEncoding]); 
NSLog(@"dataUsingEncoding UTF16: %@", [@"" dataUsingEncoding:NSUTF16BigEndianStringEncoding]); 
NSLog(@"dataUsingEncoding UTF32: %@", [@"" dataUsingEncoding:NSUTF32BigEndianStringEncoding]); 

// Для некоторых суррогатных пар не существует никакой другой формы

NSString *aReverse = [[NSString alloc] initWithBytes:"\xD8\x3C\xDD\x70\x00" length:4 encoding:NSUTF16BigEndianStringEncoding]; 
NSLog(@"character: %@", aReverse); 
NSLog(@"dataUsingEncoding UTF8: %@", [aReverse dataUsingEncoding:NSUTF8StringEncoding]); 
NSLog(@"dataUsingEncoding UTF16: %@", [aReverse dataUsingEncoding:NSUTF16BigEndianStringEncoding]); 
NSLog(@"dataUsingEncoding UTF32: %@", [aReverse dataUsingEncoding:NSUTF32BigEndianStringEncoding]); 

NSLog выход:

character: Å 
decomposedStringWithCanonicalMapping UTF8: <41cc8a> 
decomposedStringWithCanonicalMapping UTF16: <0041030a> 
decomposedStringWithCanonicalMapping UTF32: <00000041 0000030a> 

precomposedStringWithCanonicalMapping UTF8: <c385> 
precomposedStringWithCanonicalMapping UTF16: <00c5> 
precomposedStringWithCanonicalMapping UTF32: <000000c5> 

character: 
dataUsingEncoding UTF8: <f09f98b1> 
dataUsingEncoding UTF16: <d83dde31> 
dataUsingEncoding UTF32: <0001f631> 

character: 
dataUsingEncoding UTF8: <f09f85b0> 
dataUsingEncoding UTF16: <d83cdd70> 
dataUsingEncoding UTF32: <0001f170> 
+0

Это, кажется, действительно полезная информация. На данный момент я не могу проверить, потому что я не могу обновить свой MySQL на данный момент, но я собираюсь предположить, что вы правы и принимаете свой ответ :) Спасибо! – SvenM

+0

У меня есть дополнительный вопрос, если вы не возражаете. Если мне не требуется сопоставление строк, как я описал, есть ли другие недостатки, чтобы не вызывать имена наборов utf8? Я знаю, что данные вставлены неправильно, но они работают при отображении данных на клиентах. – SvenM

+0

К сожалению, я ничего не знаю о 'set names utf8', это были годы с тех пор, как я написал код для работы с MySQL. Используйте коды кода Plane 1 для тестирования (emoji находятся на плоскости 1). Также суррогатные пары, но они, вероятно, только являются проблемами для сравнения. Я добавил код и результаты в ответ, чтобы продемонстрировать различные представления в байтах юникода. – zaph