Grzegorz Krukowski
Grzegorz Krukowski

Reputation: 19792

UITextField get currently edited word

I'm working on an autocompletion component and I have one problem that I would like to solve in some easy way.

I want to support edits to autocompleted text, for example:

 blablabl @usertag blablabl

If user goes back and edits @usertag string, I would like to start autocompletion when it's edited.

Question is, how to get currently edited word from textfield. I thought about taking cursor position, seperate nsstring to word by " " (space) and count letters from first word to cursor position.

Is there any easier way for doing that?

Upvotes: 5

Views: 3410

Answers (4)

Woody Jean-louis
Woody Jean-louis

Reputation: 535

Here is a solution for the efficiency nerds. Written in Swift 4.2. I'm claiming that is is more efficient because other answers are calling the String method String.component which unnecessarily converts the entire substring to an array. Also those solutions are always grabbing words before the cursor which may not necessarily be the current word.

extension UITextView {
    /// Returns the current word that the cursor is at.
    func currentWord() -> String {
        guard let cursorRange = self.selectedTextRange else { return "" }
        func getRange(from position: UITextPosition, offset: Int) -> UITextRange? {
            guard let newPosition = self.position(from: position, offset: offset) else { return nil }
            return self.textRange(from: newPosition, to: position)
        }
    
        var wordStartPosition: UITextPosition = self.beginningOfDocument
        var wordEndPosition: UITextPosition = self.endOfDocument
    
        var position = cursorRange.start
    
        while let range = getRange(from: position, offset: -1), let text = self.text(in: range) {
            if text == " " || text == "\n" {
                wordStartPosition = range.end
                break
            }
            position = range.start
        }
    
        position = cursorRange.start
    
        while let range = getRange(from: position, offset: 1), let text = self.text(in: range) {
            if text == " " || text == "\n" {
                wordEndPosition = range.start
                break
            }
            position = range.end
        }
    
        guard let wordRange = self.textRange(from: wordStartPosition, to: wordEndPosition) else { return "" }
    
        return self.text(in: wordRange) ?? ""
    }
}

Upvotes: 4

Prashant Tukadiya
Prashant Tukadiya

Reputation: 16426

Swift 4 Solution

   func getCurrentEditingWord() ->String? {
        let selectedRange: UITextRange? = self.textView.selectedTextRange
        var cursorOffset: Int? = nil
        if let aStart = selectedRange?.start {
            cursorOffset = self.textView.offset(from: self.textView.beginningOfDocument, to: aStart)
        }
        let text = self.textView.text
        let substring = (text as NSString?)?.substring(to: cursorOffset!)
        let editedWord = substring?.components(separatedBy: " ").last
        return editedWord
    }

Upvotes: 5

Grzegorz Krukowski
Grzegorz Krukowski

Reputation: 19792

Ok I found a way to do it quite easily. Maybe someone will find it useful:

UITextRange* selectedRange = [textField selectedTextRange];
NSInteger cursorOffset = [textField offsetFromPosition:0 toPosition:selectedRange.start];
NSString* text = textField.text;
NSString* substring = [text substringToIndex:cursorOffset];
NSString* editedWord = [[substring componentsSeparatedByString:@" "] lastObject];

Upvotes: 8

A Salcedo
A Salcedo

Reputation: 6468

Have you tried using UITextFieldDelegate available methods? If access to the word as you edit it is what you want, you can simply use the -textField:shouldChangeCharactersInRange:replacementString: Inside this method you have access to the string as it's entered, and you can also do any string manipulation here for every new character entered.

Upvotes: 0

Related Questions