A truncation string containing emoji or unicode characters in a word or character boundaries

The problemm

How can I truncate a string with a given length without invalidating the unicode character, which could be a hit in the middle of my length? How to determine the index of the beginning of a Unicode character in a string so that I can avoid creating ugly strings. A square with half visible A is the location of another emoji symbol that has been truncated.

-(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 . Thanks to the answer, I was able to use one simple function for my needs!

 -(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; } 
+9
ios objective-c unicode nsstring emoji
Apr 02 '13 at
source share
2 answers

NSString has a rangeOfComposedCharacterSequencesForRange method, which you can use to find the spanning range in a string containing only complete, composed characters. for example

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

gives a range of { 0, 2 } , because the Emoji character is stored as two UTF-16 characters (surrogate pair) in a string.

Note. You can also check if you can simplify your first cycle using

 enumerateSubstringsInRange:options:usingBlock 

with the option NSStringEnumerationByWords .

+14
Apr 03 '13 at 5:23
source share
— -

"trim string with a given length" <- Do you mean the length in length or length of the byte, as well as in the number of characters? If the latter, then simply substringToIndex: will be enough (check the borders first). If the first one, then I'm afraid you will need something like:

 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: Your code can be rewritten as follows:

 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:@" "]]; 
+2
Apr 03 '13 at 2:00
source share



All Articles