2013-04-02 6 views
9

The Problemstringa Tronca contenente caratteri emoji o Unicode in parola o il carattere confini

Come posso troncare una stringa in una data lunghezza, senza annientare un carattere Unicode che potrebbe essere nel bel mezzo della mia lunghezza? Come si può determinare l'indice dell'inizio di un carattere unicode in una stringa in modo da evitare di creare stringhe brutte. Il quadrato con metà di A visibile è la posizione di un altro personaggio emoji che è stato troncato.

-(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; 

} 

AGGIORNAMENTO Grazie alla risposta, era in grado di utilizzare una semplice funzione per le mie esigenze!

-(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; 

} 

risposta

14

NSString ha un metodo che rangeOfComposedCharacterSequencesForRange puoi usare per trovare l'intervallo che racchiude nella stringa che contiene solo caratteri composti completi. Ad esempio

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

dà l'intervallo { 0, 2 } poiché il carattere Emoji viene memorizzato come due UTF-16 caratteri (coppia surrogata) nella stringa.

Nota: Si potrebbe anche verificare se è possibile semplificare il vostro primo ciclo utilizzando

enumerateSubstringsInRange:options:usingBlock 

con l'opzione NSStringEnumerationByWords.

+0

Grazie, Martin! –

2

"troncare una stringa ad una data lunghezza" < - Vuoi dire lunghezza in byte di lunghezza o la lunghezza come nel numero di caratteri? In quest'ultimo caso, sarà sufficiente un semplice substringToIndex: (controllare prima i limiti). Nel primo caso, allora temo che dovrete fare qualcosa di simile:

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: Il codice può essere riscritta come segue:

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

Inizialmente utilizzavo la sottostringaWithRange e tagliava un carattere unicode letteralmente a metà, per mancanza di una spiegazione migliore. Non so che substringToIndex preserverebbe il personaggio. Pensieri? –

+0

Ho appena provato substringToIndex e ho avuto gli stessi sfortunati risultati della sottostringaWithRange –

+0

Hm ... come stai creando il tuo 'NSString'? Sei sicuro di aver specificato la codifica corretta durante la sua creazione? – fumoboy007