截断在单词或字符边界处包含表情符号或unicode字符的string

问题

我怎样才能截断一个string在给定的长度,而不消灭一个unicode字符,可能会在我的长度中间? 如何确定一个string中的Unicode字符的开始索引,以便我可以避免创build丑陋的string。 一半可见的正方形是已被截断的另一表情符号的位置。

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

更新感谢答复,能够使用一个简单的function,我的需要!

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

NSString有一个方法rangeOfComposedCharacterSequencesForRange ,您可以使用该方法来查找仅包含完整组合字符的string中的封闭范围。 例如

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

给出范围{ 0, 2 }因为表情符号字符在string中存储为两个UTF-16字符(代理对)。

备注:你也可以通过使用来检查你是否可以简化你的第一个循环

 enumerateSubstringsInRange:options:usingBlock 

NSStringEnumerationByWords选项。

“以给定的长度截断string”< – 您的意思是字节长度或字符长度的长度? 如果是后者,那么一个简单的substringToIndex:就足够了(尽pipe先检查边界)。 如果前者,那么恐怕你将不得不这样做:

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

编辑:您的代码可以被重写如下:

 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:@" "]];