How can I truncate an NSString to a set length?
IphoneObjective CCocoaStringIphone 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];