Fast Line Count

Anyone have a Swift (or ObjC) method to QUICKLY count the number of lines (\n) in an NSString?

The only method I’ve found so far is the equivalent of "split

Well, split IS pretty fast. Do you actually need to optimize this or are you trying to optimize the wrong part?

I need to update the line count whenever is could have possibly changed. So it needs to be rather quick, and keep a low footprint (a split duplicates the contents), and this string could be close to a meg . Right now I am trying to attach the recalcuation to everytime the user types [RETURN] or [BACKSPACE] (but also need to detect cuts and pastes)

The only other alternative is to just do it when ever the text changes, but that is quite often

came up with a way that seems to work

  1. if the user type [Return], [BS] or pastes then a flag is set
  2. in the textchange event if the flag is set it executes a RegEx
func textView(_ textView: NSTextView, shouldChangeTextIn affectedCharRange: NSRange, replacementString: String?) -> Bool {
    let s : String = String(replacementString!)
   if s.isEmpty || s=="\n" || s.count>1 { needRecount=true }
    return true
}

 func textDidChange(_ notification: Notification) {  // this fires is user TYPES into field
            if needRecount {
                let s       = self.string
                let regex   = try! NSRegularExpression(pattern:("(\\n)|(\\r)|(\\r\\n)"))
                let matchs  = regex.matches(in: s, range: NSRange(location: 0, length: s.count))//.map{(s as NSString).substring(with: $0.range)}
                print(matchs.count) <---- LINE COUNT IS HERE
                needRecount=false
            }
            self.needsDisplay=true
}

So it needs to be rather quick,

Can you do that in a thread that starts after the user types anything?

The above method is very fast, 30K lines in a split second…
BUT the answer is wrong… :frowning:
My text has 34783 lines, but the count returns as only 30442
mis counted by 4000 lines!

OR my linenumber display is wrong… guess I better figure out which it is :frowning:

So it could be faster…

650k lines counted in 0.74 seconds, that would create a bit of a lag in typing on a large file

WOW!!!
found a method that counted 1,564,850 lines in 0.14 seconds!!!

I think I’ll keep this one … (sorry guys, won’t work for Xojo)

func countLines(textView: NSTextView) -> Int {
    let layoutManager  = textView.layoutManager
    var numberOfLines  = 0
    var index          = 0
    var lineRange      = NSRange()
    let numberOfGlyphs = layoutManager!.numberOfGlyphs
    while index < numberOfGlyphs {
        numberOfLines += 1
        layoutManager!.lineFragmentRect(forGlyphAt: index, effectiveRange: &lineRange)
        index = NSMaxRange(lineRange);
    }
    print(numberOfLines)
    return numberOfLines
}
1 Like

Drag&drop?

Its tied to the TEXTCHANGE event… so drag&drop, paste, cut, type etc…

Ah, ok. You said earlier that you relied on key presses (see what I quoted from you), so I wondered…

Sorry… I solved that issue after I entered all that :slight_smile:

1 Like