如何将 NSString 截断为设定长度?

问题描述 投票:0回答:12

我进行了搜索,但令人惊讶的是找不到答案。

我有一个很长的

NSString
,我想缩短。我希望最大长度约为 20 个字符。我在某处读到最好的解决方案是使用
substringWithRange
。这是截断字符串的最佳方法吗?

NSRange stringRange = {0,20};
NSString *myString = @"This is a string, it's a very long string, it's a very long string indeed";
NSString *shortString = [myString substringWithRange:stringRange];

看起来有点微妙(如果字符串短于最大长度就会崩溃)。我也不确定它是否是 Unicode 安全的。有更好的方法吗?有人有一个很好的类别吗?

iphone objective-c cocoa string
12个回答
123
投票

实际上,关于“Unicode 安全”的部分是完全正确的,因为许多字符在 unicode 中组合,而建议的答案没有考虑到。

例如,如果您想输入 é。一种方法是输入“e”(0x65)+组合重音符号“́”(0x301)。现在,如果您像这样输入“café”并截断 4 个字符,您将得到“cafe”。这可能会在某些地方引起问题。

如果你不关心这个,其他答案也可以。否则,请执行以下操作:

// define the range you're interested in
NSRange stringRange = {0, MIN([myString length], 20)};

// adjust the range to include dependent chars
stringRange = [myString rangeOfComposedCharacterSequencesForRange:stringRange];

// Now you can create the short string
NSString *shortString = [myString substringWithRange:stringRange];

请注意,这样您的范围可能会比您的初始范围长度更长。在上面的咖啡馆示例中,您的范围将扩展到长度 5,即使您仍然有 4 个“字形”。如果您绝对需要的长度小于您指定的长度,则需要检查这一点。


25
投票

斯威夫特4

let trimToCharacter = 20
let shortString = String(myString.prefix(trimToCharacter))

快乐编码。


15
投票

由于这个答案实际上并不在此列表中,所以最简单、最明智的一句话:

NSString *myString = @"This is a string, it's a very long string, it's a very long string indeed";
myString = (myString.length > 20) ? [myString substringToIndex:20] : myString;

11
投票

更短的解决方案是:

NSString *shortString = ([myString length]>MINLENGTH ? [myString substringToIndex:MINLENGTH] : myString);

7
投票

看起来有点精致(如果字符串短于最大长度就会崩溃)

那为什么不修复那部分呢?

NSRange stringRange = {0, MIN([myString length], 20)};

3
投票

可以使用三元运算:

NSString *shortString = (stringRange.length <= [myString length]) ? myString : [myString substringWithRange:stringRange];

或者更好地控制最终结果:

if (stringRange.length > [myString length])
    // throw exception, ignore error, or set shortString to myString
else 
    shortString = [myString substringWithRange:stringRange];

3
投票

扩展以在不同位置(头部、尾部或中间)截断。

Swift 4.2 及更高版本

extension String {
    enum TruncationPosition {
        case head
        case middle
        case tail
    }

   func truncated(limit: Int, position: TruncationPosition = .tail, leader: String = "...") -> String {
        guard self.count >= limit else { return self }

        switch position {
        case .head:
            return leader + self.suffix(limit)
        
        case .middle:
            let halfCount = (limit - leader.count).quotientAndRemainder(dividingBy: 2)
            let headCharactersCount = halfCount.quotient + halfCount.remainder
            let tailCharactersCount = halfCount.quotient
            return String(self.prefix(headCharactersCount)) + leader + String(self.suffix(tailCharactersCount))
        
        case .tail:
            return self.prefix(limit) + leader
        }
    }
}

3
投票

最简单又漂亮的解决方案(文本末尾有3个点):

NSString *newText = [text length] > intTextLimit ? 
    [[text substringToIndex:intTextLimit] stringByAppendingString:@"…"] : 
        text;

2
投票
 //Short the string if string more than 45 chars
    if([self.tableCellNames[indexPath.section] length] > 40) {

        // define the range you're interested in
        NSRange stringRange = {0, MIN([self.tableCellNames[indexPath.section] length], 40)};

        // adjust the range to include dependent chars
        stringRange = [self.tableCellNames[indexPath.section]
                       rangeOfComposedCharacterSequencesForRange:stringRange];

        // Now you can create the short string
        NSString *shortStringTitle = [self.tableCellNames[indexPath.section] substringWithRange:stringRange];

        shortStringTitle = [shortStringTitle stringByAppendingString:@"..."];

        titleLabel.text = shortStringTitle;

    } else {

        titleLabel.text = self.tableCellNames[indexPath.section];
    }

//VKJ


0
投票

所有 NSString 操作都是 Unicode 安全的,因为 NSString 内部本质上是一个 unichar 数组。即使字符串采用不同的编码,它在显示时也会转换为您指定的编码。


0
投票

如果您想从最终使用中截断:

[fileName substringToIndex:anyNumber];

如果你想从头开始截断:

[fileName substringFromIndex:anyNumber];

0
投票

使用

NSLineBreakMode
定义截断模式,您可以截断字符串,如下所示:

"a really long text to truncate with the given modes"
,,,

.truncated(.byClipping, to: 20))           // a really long text t

.truncated(.byWordWrapping, to: 20))       // a really long...

.truncated(.byTruncatingTail, to: 20))     // a really long tex...

.truncated(.byTruncatingMiddle, to: 20))   // a really...ven modes
  
.truncated(.byTruncatingHead, to: 20))     // ...h the given modes

这是背后的扩展:

extension String {
    func truncated(_ mode: NSLineBreakMode = .byTruncatingTail, to maxLength: Int, truncatingSign: Self = "...") -> Self {
        guard self.count > maxLength else { return self }
        let visibleCount = maxLength - truncatingSign.count

        switch mode {
        case .byWordWrapping:
            let mutatedSelf = self.prefix(visibleCount)
            let nLastChar = self.index(after: mutatedSelf.endIndex)
            guard self[nLastChar].isWhitespace else { return mutatedSelf + truncatingSign }

            var lastWord: String = ""
            mutatedSelf.enumerateSubstrings(in: startIndex..., options: [.byWords, .reverse]) { (substring , _, _, stop) in
                guard let substring = substring else { return }
                lastWord = substring
                stop = true
            }

            if let range = mutatedSelf.range(of: lastWord, options: .backwards, range: nil, locale: nil) {
                return mutatedSelf
                    .replacingCharacters(in: range, with: "")
                    .replacingOccurrences(of: "\\s+$", with: "", options: .regularExpression)
                    + truncatingSign
            }

            return mutatedSelf + truncatingSign
        case .byCharWrapping: return self.prefix(visibleCount) + truncatingSign
        case .byClipping: return self.prefix(maxLength) + ""
        case .byTruncatingHead: return truncatingSign + self.suffix(visibleCount)
        case .byTruncatingTail: return self.prefix(visibleCount) + truncatingSign
        case .byTruncatingMiddle:
            let middle = Double(visibleCount)/2
            return self.prefix(Int(middle.rounded(.down))) + ""
            + truncatingSign
            + self.suffix(Int(middle.rounded(.up))) + ""
        @unknown default: return self /* Future unknown case */
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.