28

I want to count the lines in an NSString in Objective-C.

  NSInteger lineNum = 0;
  NSString *string = @"abcde\nfghijk\nlmnopq\nrstu";
  NSInteger length = [string length];
  NSRange range = NSMakeRange(0, length);
  while (range.location < length) {
      range = [string lineRangeForRange:NSMakeRange(range.location, 0)];
      range.location = NSMaxRange(range);
      lineNum += 1;
  }

Is there an easier way?

freddiefujiwara
  • 57,041
  • 28
  • 76
  • 106

3 Answers3

46

Apple recommends this method:

NSString *string;
unsigned numberOfLines, index, stringLength = [string length];

for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++)
    index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]);

See the article. They also explain how to count lines of wrapped text.

Lukáš Kubánek
  • 946
  • 1
  • 15
  • 27
Loda
  • 1,970
  • 2
  • 20
  • 40
  • Probably would be a good idea to initialise the string for the sample, infinite loop without a nil check. – malhal Jul 24 '15 at 00:16
  • The only thing this account for was strings that started/ended with a new line. To fix this I added the following: `NSString *string = @"this is \nyour string\n"; NSInteger numberOfLines, index, stringLength = [string length]; for (index = 0, numberOfLines = 0; index < stringLength; numberOfLines++) index = NSMaxRange([string lineRangeForRange:NSMakeRange(index, 0)]); if([string hasSuffix:@"\n"] || [string hasSuffix:@"\r"]) numberOfLines += 1; if([string hasPrefix:@"\n"] || [string hasPrefix:@"\r"]) numberOfLines += 1; return numberOfLines;` – Travis Weerts Oct 10 '15 at 19:45
37

well, a not very efficient, but nice(ish) looking way is

NSString *string = @"abcde\nfghijk\nlmnopq\nrstu";
NSInteger length = [[string componentsSeparatedByCharactersInSet:
                                [NSCharacterSet newlineCharacterSet]] count];

Swift 4:

myString.components(separatedBy: .newlines)
Jack
  • 13,571
  • 6
  • 76
  • 98
cobbal
  • 69,903
  • 20
  • 143
  • 156
  • Thank you ! ! In Above case, how to code? Sorry I'm begginner for Programming – freddiefujiwara Jul 06 '09 at 05:36
  • 4
    Bear in mind that if the string is very long, this will be *much* less efficient than code like what you posted in the question, since it will create a new string object for every line. Be sure you understand how important performance is where you are doing this, and what the upper bound on the string size will be. – smorgan Jul 06 '09 at 14:52
5

If you want to take into account the width of the text, you can do this with TextKit (iOS7+):

func numberOfLinesForString(string: String, size: CGSize, font: UIFont) -> Int {
    let textStorage = NSTextStorage(string: string, attributes: [NSFontAttributeName: font])

    let textContainer = NSTextContainer(size: size)
    textContainer.lineBreakMode = .ByWordWrapping
    textContainer.maximumNumberOfLines = 0
    textContainer.lineFragmentPadding = 0

    let layoutManager = NSLayoutManager()
    layoutManager.textStorage = textStorage
    layoutManager.addTextContainer(textContainer)

    var numberOfLines = 0
    var index = 0
    var lineRange : NSRange = NSMakeRange(0, 0)
    for (; index < layoutManager.numberOfGlyphs; numberOfLines++) {
        layoutManager.lineFragmentRectForGlyphAtIndex(index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange)
    }

    return numberOfLines
}
johnboiles
  • 3,494
  • 1
  • 32
  • 26