10

问题

如何截断给定长度的字符串,而不消除可能在我的长度中间的 unicode 字符?如何确定字符串中 unicode 字符开头的索引,以便避免创建难看的字符串。有一半 A 可见的正方形是另一个已被截断的表情符号字符的位置。

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

}

更新感谢答案,能够使用一个简单的功能来满足我的需求!

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

}
4

2 回答 2

17

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

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

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

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

enumerateSubstringsInRange:options:usingBlock

NSStringEnumerationByWords选项。

于 2013-04-03T05:23:36.380 回答
2

“以给定长度截断字符串”<-您的意思是长度为字节长度还是长度为字符数?如果是后者,那么一个简单的substringToIndex:就足够了(尽管先检查边界)。如果是前者,那么恐怕您必须执行以下操作:

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:@" "]];
于 2013-04-03T02:00:48.847 回答