2016-06-30 7 views
3

Ich habe die Zeichenfolge @"Hi there! \U0001F603", die die Emoji wie Hi there! korrekt zeigt, wenn ich es in eine UILabel setzen.Dynamisch erstellen NSString mit Unicode Emoji

Aber ich möchte es dynamisch wie [NSString stringWithFormat:@"Hi there! \U0001F60%ld", (long)arc4random_uniform(10)] erstellen, aber es kompiliert nicht. Wenn ich den umgekehrten Schrägstrich verdoppeln, zeigt es den Unicode-Wert buchstäblich wie Hi there! \U0001F605.

Wie kann ich das erreichen?

Antwort

1

Ein Schritt zurück für eine zweite: die Zahl, die Sie haben, 1F6603 , ist ein Unicode Codepunkt, die, zu versuchen Sie es so einfach wie möglich zu sagen, ist der Index dieses Emoji in der Liste aller Unicode-Elemente. Das ist nicht dasselbe wie die Bytes, die der Computer tatsächlich behandelt, die den "codierten Wert" (technisch, der Code Einheiten.

Wenn Sie die wörtliche@"\U0001F603" in Ihrem Code zu schreiben, hat der Compiler die Codierung für Sie, das notwendige Bytes zu schreiben. * Wenn Sie bei der Kompilierung nicht die wörtliche haben, müssen Sie die Codierung selbst tun. Das heißt, Sie müssen den Codepunkt in eine Menge von Bytes umwandeln, die ihn darstellen. In der UTF-16-Codierung, die NSString intern verwendet, wird Ihr Codepunkt beispielsweise durch die Bytes ff fe 3d d8 03 de dargestellt.

Sie können dieses Literal zur Laufzeit nicht ändern und enden mit den richtigen Bytes, weil der Compiler seine Arbeit bereits erledigt hat und ins Bett gegangen ist.

(Sie können über diese Dinge in der Tiefe lesen und wie es bezieht sich auf NSString in an article by Ole Begemann at objc.io.)

Zum Glück, eine der verfügbaren Kodierungen UTF-32, stellt Codepunkte direkt: der Wert der Bytes das gleiche wie der Code-Punkt. Mit anderen Worten, wenn Sie Ihre Codepunktnummer einer 32-Bit-Ganzzahl ohne Vorzeichen zuordnen, verfügen Sie über geeignete UTF-32-kodierte Daten.

Das führt uns auf den Prozess führt Sie brauchen:

// Encoded start point 
uint32_t base_point_UTF32 = 0x1F600; 

// Generate random point 
uint32_t offset = arc4random_uniform(10); 
uint32_t new_point = base_point_UTF32 + offset; 

// Read the four bytes into NSString, interpreted as UTF-32LE. 
// Intel machines and iOS on ARM are little endian; others byte swap/change 
// encoding as necessary. 
NSString * emoji = [[NSString alloc] initWithBytes:&new_point 
              length:4 
              encoding:NSUTF32LittleEndianStringEncoding]; 

(. NB, dass dies nicht als für einen beliebigen Code Punkt erwartet funktionieren, nicht alle Codepunkte gültig sind)


* Beachten Sie, dass dies auch für "normale" Strings wie @"b" gilt.

+0

Tolle Erklärung, vielen Dank! –

+0

Konnten Sie mir mit [dieser Frage] (http://stackoverflow.com/questions/38181966/print-unicode-emoji-from-api-response) auch helfen? –

3

\U0001F603 ist ein Literal, das zur Kompilierzeit ausgewertet wird. Sie möchten eine Lösung, die zur Laufzeit ausgeführt werden kann.

Sie möchten also eine Zeichenfolge mit einem dynamischen Unicode-Zeichen haben. %C Wenn der Formatbezeichner für ein Unicode-Zeichen ( unichar).

[NSString stringWithFormat:@"Hi there! %C", (unichar)(0x01F600 + arc4random_uniform(10))]; 

unichar ist zu klein für Emoji. Danke @JoshCaswell für die Korrektur.


Update: eine Arbeits Antwort

@JoshCaswell hat die richtige Antwort mit -initWithBytes:length:encoding:, aber ich denke, ich kann eine bessere Wrapper schreiben.

  1. Erstellen Sie eine Funktion für alle Arbeiten.
  2. Verwenden Sie network ordering für eine Standard-Byte-Reihenfolge.
  3. Keine magische Zahl für die Länge.

Hier ist meine Antwort

NSString *MyStringFromUnicodeCharacter(uint32_t character) { 
    uint32_t bytes = htonl(character); // Convert the character to a known ordering 
    return [[NSString alloc] initWithBytes:&bytes length:sizeof(uint32_t) encoding:NSUTF32StringEncoding]; 
} 

Also, im Einsatz ...

NSString *emoji = MyStringFromUnicodeCharacter(0x01F600 + arc4random_uniform(10)); 
NSString *message = [NSString stringWithFormat:@"Hi there! %@", emoji]; 

Update 2

schließlich in eine Kategorie gesetzt es wirklich zu machen Ziel c.

@interface NSString (MyString) 
+ (instancetype)stringWithUnicodeCharacter:(uint32_t)character; 
@end 
@implementation NSString (MyString) 
+ (instancetype)stringWithUnicodeCharacter:(uint32_t)character { 
    uint32_t bytes = htonl(character); // Convert the character to a known ordering 
    return [[NSString alloc] initWithBytes:&bytes length:sizeof(uint32_t) encoding:NSUTF32StringEncoding]; 
} 
@end 

Und wieder im Einsatz ...

NSString *emoji = [NSString stringWithUnicodeCharacter:0x01F600 + arc4random_uniform(10)]; 
NSString *message = [NSString stringWithFormat:@"Hi there! %@", emoji]; 
+0

Es zeigt sich wie '' (ein Quadrat mit einem Fragezeichen drin), anstelle des Emoji –

+0

@IulianOnOfrei stellen Sie sicher, dass Sie '0x01F600' haben. Als ich das erste Mal gepostet habe, hatte ich '0x01F60' aus Versehen. –

+0

Ich sah, dass Sie Ihre Antwort bearbeitet haben, und ich habe tatsächlich '0x01F600' –