如何缩短可能包含的NSString表情符号到HFS +文件名允许的最大长度

时间:2015-07-30 20:09:20

标签: ios macos cocoa nsstring foundation

苹果文档说:

  

[...]当前的文件系统,如HFS +(由Mac OS X使用),允许您创建具有255个字符限制的文件名[...]符号实际上可能需要相当于9个英文字符store [...]尝试创建更长的名称时应考虑这一点。

如何以真正短于255个字符的方式限制NSString的长度,即使它包含可能需要存储多个字符的符号?

我在下面添加我当前的实现。如果我添加例如emojis到字符串,而length回答结果字符串远远小于255,它仍然太长,不能被NSSavePanel作为文件名接受。

NSRange stringRange = {0, MIN([fileName length], 255)};
stringRange = [fileName rangeOfComposedCharacterSequencesForRange:stringRange];
fileName = [fileName substringWithRange:stringRange];

2 个答案:

答案 0 :(得分:2)

根据@JoshCaswell的建议,我确实将this answer修改为类似的问题。它显然是有效的(我写了几个测试),但它对我来说似乎很奇怪。这样一个明显的任务实现起来不是那么复杂吗?

// filename contains the NSString that should be shortened
NSMutableString *truncatedString = [NSMutableString string];
NSUInteger bytesRead = 0;
NSUInteger charIdx = 0;

while (bytesRead < 250 && charIdx < [fileName length])
{
    NSRange range = [fileName rangeOfComposedCharacterSequencesForRange:NSMakeRange(charIdx, 1)];
    NSString *character = [fileName substringWithRange:NSMakeRange(charIdx, range.length)];
    bytesRead += [character lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
    charIdx = charIdx + range.length;
    if (bytesRead <= 250)
        [truncatedString appendString:character];
}

答案 1 :(得分:1)

rangeOfComposedCharacterSequencesForRange:基本上与你想要的相反:你给它一个计算255个组合字符的范围,它给你包含那些的字节范围,这可能最终比你想要的多得多

不幸的是,反过来,你必须手动计算字节数。但是,enumerateSubstringsInRange:options:usingBlock:并不太难。为选项传递NSStringEnumerationByComposedCharacterSequences可以准确地说明它所说的内容:每个组成的角色依次。然后,您可以使用lengthOfBytesUsingEncoding:计算每个的大小,并传递您将使用的最终编码(可能是UTF-8)。添加字节,跟踪基于字符的索引,并在看到太多时停止。

NSString * s = /* String containing multibyte characters */;
NSUInteger maxBytes = ...;
__block NSUInteger seenBytes = 0;
__block NSUInteger truncLength = 0;
NSRange fullLength = (NSRange){0, [s length]};

[s enumerateSubstringsInRange:fullLength
                      options:NSStringEnumerationByComposedCharacterSequences
                   usingBlock:
    ^(NSString *substring, NSRange substringRange,
      NSRange _, BOOL *stop)
    {
        seenBytes += [substring lengthOfBytesUsingEncoding:NSUTF8StringEncoding];
        if( seenBytes > maxBytes ){
            *stop = YES;
            return;
        }
        else {
            truncLength += substringRange.length;
        }
}];

NSString * truncS = [s substringToIndex:truncLength];