2013-04-02 8 views
9

The ProblemKürzen String mit Emojis oder Unicode-Zeichen an Wort- oder Zeichengrenzen

Wie kann ich eine Zeichenfolge an einer bestimmten Länge ohne vernichtend ein Unicode-Zeichen gestutzt, die genau in der Mitte meiner Länge sein könnten? Wie kann man den Index des Anfangs eines Unicode-Zeichens in einer Zeichenkette bestimmen, so dass ich die Erzeugung hässlicher Zeichenketten vermeiden kann? Das Quadrat mit der Hälfte eines sichtbaren A ist die Position eines anderen Emoji-Zeichens, das abgeschnitten wurde.

-(NSMutableAttributedString*)constructStatusAttributedStringWithRange:(CFRange)range 

NSString *original = [_postDictionay objectForKey:@"message"]; 

NSMutableString *truncated = [NSMutableString string]; 

NSArray *components = [original componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 

for(int x=0; x<[components count]; x++) 
{ 
    //If the truncated string is still shorter then the range desired. (leave space for ...) 
    if([truncated length]+[[components objectAtIndex:x] length]<range.length-3) 
    { 
     //Just checking if its the first word 
     if([truncated length]==0 && x==0) 
     { 
      //start off the string 
      [truncated appendString:[components objectAtIndex:0]]; 
     } 
     else 
     { 
      //append a new word to the string 
      [truncated appendFormat:@" %@",[components objectAtIndex:x]]; 
     } 

    } 
    else 
    { 
     x=[components count]; 
    } 
} 

if([truncated length]==0 || [truncated length]< range.length-20) 
{ 
    truncated = [NSMutableString stringWithString:[original substringWithRange:NSMakeRange(range.location, range.length-3)]]; 
} 

[truncated appendString:@"..."]; 

NSMutableAttributedString *statusString = [[NSMutableAttributedString alloc]initWithString:truncated]; 
[statusString addAttribute:(id)kCTFontAttributeName value:[StyleSingleton streamStatusFont] range:NSMakeRange(0, [statusString length])]; 
[statusString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[StyleSingleton streamStatusColor].CGColor range:NSMakeRange(0, [statusString length])]; 

return statusString; 

} 

UPDATE Dank der Antwort, konnte für meine Bedürfnisse eine einfache Funktion nutzen!

-(NSMutableAttributedString*)constructStatusAttributedStringWithRange:(CFRange)range 
{ 
NSString *original = [_postDictionay objectForKey:@"message"]; 

NSMutableString *truncated = [NSMutableString stringWithString:[original substringWithRange:[original rangeOfComposedCharacterSequencesForRange:NSMakeRange(range.location, range.length-3)]]]; 
[truncated appendString:@"..."]; 

NSMutableAttributedString *statusString = [[NSMutableAttributedString alloc]initWithString:truncated]; 
[statusString addAttribute:(id)kCTFontAttributeName value:[StyleSingleton streamStatusFont] range:NSMakeRange(0, [statusString length])]; 
[statusString addAttribute:(id)kCTForegroundColorAttributeName value:(id)[StyleSingleton streamStatusColor].CGColor range:NSMakeRange(0, [statusString length])]; 

return statusString; 

} 

Antwort

14

NSString hat eine Methode rangeOfComposedCharacterSequencesForRange dass Sie können den umschließenden Bereich in der Zeichenfolge suchen, die nur vollständig zusammengesetzte Zeichen enthält. Zum Beispiel

NSString *s = @""; 
NSRange r = [s rangeOfComposedCharacterSequencesForRange:NSMakeRange(0, 1)]; 

gibt den Bereich { 0, 2 } weil die Emoji Zeichen als zwei UTF-16 Zeichen gespeichert (Surrogat-Paar) in der Zeichenkette.

Bemerkung: Sie können auch überprüfen, ob Sie Ihre erste Schleife

durch die Verwendung vereinfachen
enumerateSubstringsInRange:options:usingBlock 

mit der NSStringEnumerationByWords Option.

+0

Danke Martin! –

2

„eine Zeichenfolge an einer bestimmten Länge gestutzt“ < - Meinen Sie Länge wie in Byte Länge oder Länge wie in Anzahl von Zeichen? Wenn letzteres ausreicht, dann genügt ein einfacher substringToIndex: (überprüfen Sie jedoch zuerst die Grenzen). Wenn der ehemalige, dann fürchte ich werde Sie zu tun haben, so etwas wie:

NSString *TruncateString(NSString *original, NSUInteger maxBytesToRead, NSStringEncoding targetEncoding) { 
    NSMutableString *truncatedString = [NSMutableString string]; 

    NSUInteger bytesRead = 0; 
    NSUInteger charIdx = 0; 

    while (bytesRead < maxBytesToRead && charIdx < [original length]) { 
     NSString *character = [original substringWithRange:NSMakeRange(charIdx++, 1)]; 

     bytesRead += [character lengthOfBytesUsingEncoding:targetEncoding]; 

     if (bytesRead <= maxBytesToRead) 
      [truncatedString appendString:character]; 
    } 

    return truncatedString; 
} 

EDIT: kann Ihr Code neu geschrieben werden wie folgt:

NSString *original = [_postDictionay objectForKey:@"message"]; 

NSArray *characters = [[original componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]] filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"SELF != ''"]]; 

NSArray *truncatedCharacters = [characters subarrayWithRange:range]; 

NSString *truncated = [NSString stringWithFormat:@"%@...", [truncatedCharacters componentsJoinedByString:@" "]]; 
+0

Ich verwendete ursprünglich substringWithRange, und es würde ein Unicode-Zeichen buchstäblich in zwei Hälften schneiden, aus Mangel an einer besseren Erklärung. Ich weiß nicht, dass substringToIndex das Zeichen erhalten würde. Gedanken? –

+0

Gerade versucht substringToIndex, und hatte die gleichen unglücklichen Ergebnisse wie mit substringWithRange –

+0

Hm ... Wie erstellen Sie Ihre 'NSString'? Sind Sie sicher, dass Sie beim Erstellen die richtige Codierung angegeben haben? – fumoboy007