How can I truncate an NSString to a set length?

IphoneObjective CCocoaString

Iphone Problem Overview


I searched, but surprisingly couldn't find an answer.

I have a long NSString that I want to shorten. I want the maximum length to be around 20 characters. I read somewhere that the best solution is to use substringWithRange. Is this the best way to truncate a string?

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

It seems a little delicate (crashes if the string is shorter than the maximum length). I'm also not sure if it's Unicode-safe. Is there a better way to do it? Does anyone have a nice category for this?

Iphone Solutions


Solution 1 - Iphone

Actually the part about being "Unicode safe" was dead on, as many characters combine in unicode which the suggested answers don't consider.

For example, if you want to type é. One way of doing it is by typing "e"(0x65)+combining accent" ́"(0x301). Now, if you type "café" like this and truncate 4 chars, you'll get "cafe". This might cause problems in some places.

If you don't care about this, other answers work fine. Otherwise, do this:

// 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];

Note that in this way your range might be longer than your initial range length. In the café example above, your range will expand to a length of 5, even though you still have 4 "glyphs". If you absolutely need to have a length less than what you indicated, you need to check for this.

Solution 2 - Iphone

Swift 4

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

Happy Coding.

Solution 3 - Iphone

Since this answer isn't actually in this list, the simplest and most sensible one-liner:

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;

Solution 4 - Iphone

A shorter solution is:

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

Solution 5 - Iphone

> It seems a little delicate (crashes if the string is shorter than the maximum length)

Then why not fix that part of it?

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

Solution 6 - Iphone

Could use a ternary operation:

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

Or for more control over the end result:

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

Solution 7 - Iphone

The simplest and nice solution (with 3 dots at the end of the text) :

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

Solution 8 - Iphone

 //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

Solution 9 - Iphone

Extension to truncate at different positions (head, tail or middle).

Swift 4.2 and newer

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

Solution 10 - Iphone

All NSString operations are Unicode-safe, as NSString is essentially a unichar array internally. Even if the string is in a different encoding it's converted to your specified encoding when it's displayed.

Solution 11 - Iphone

If you want to truncate from end use:

[fileName substringToIndex:anyNumber];

If you want to truncate from start:

[fileName substringFromIndex:anyNumber];

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionnevan kingView Question on Stackoverflow
Solution 1 - IphonemohsenrView Answer on Stackoverflow
Solution 2 - IphoneMd. Ibrahim HassanView Answer on Stackoverflow
Solution 3 - IphonebrandonscriptView Answer on Stackoverflow
Solution 4 - IphonePhoenixView Answer on Stackoverflow
Solution 5 - IphoneShaggy FrogView Answer on Stackoverflow
Solution 6 - IphoneAlex ReynoldsView Answer on Stackoverflow
Solution 7 - IphoneYossiView Answer on Stackoverflow
Solution 8 - IphoneVinod JoshiView Answer on Stackoverflow
Solution 9 - IphoneKedar SukerkarView Answer on Stackoverflow
Solution 10 - IphoneJon ShierView Answer on Stackoverflow
Solution 11 - IphoneGauravView Answer on Stackoverflow