Search code examples
iosswiftuikituitextfielduilabel

How can I compare characters in Swift? I have UILabel with text and UITextField


So I have a UILabel with text which I have to write in UITextField for check are the characters of UILabel and UITextField are similar? So I have some practice in C-Lang and in C-lang to solve this we have to write Integer indices to compare the indices in "UILabel" from "UITextField". So we have a characters and if characters in label and textfield are the same we just increment an index and have to compare the next index(character).

I need to compare each character. For example, we have a string "Hello!". And if we write "Heklo?", our characters "H", "e", "l", "o" must be green and our "k" and "?" must be red.

In swift I tried to do the same but it doesnt work.

import UIKit

class ViewController: UIViewController {    
    private let textLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.translatesAutoresizingMaskIntoConstraints = false
        label.text = "There are a text, which you must text to get the last character of this label!"
        label.sizeToFit()
        return label
    }()
    private let resultTextLabel: UILabel = {
        let label = UILabel()
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.translatesAutoresizingMaskIntoConstraints = false
        label.sizeToFit()
        return label
    }()
    private let textField : UITextField = {
        let text = UITextField(frame: CGRect(x: 20, y: 300, width: 300, height: 40))
        text.placeholder = "Enter text Here!"
        text.font = .systemFont(ofSize: 15)
        text.autocorrectionType = .no
        text.keyboardType = .default
        text.returnKeyType = .done
        text.clearButtonMode = .whileEditing
        text.addTarget(self, action: #selector(checkWrongOrRight), for: .editingChanged)
        return text
    }()
    override func viewDidLoad() {
        super.viewDidLoad()
        view.addSubview(textLabel)
        view.addSubview(textField)
        view.addSubview(resultTextLabel)
        setUpConstraints()
    }
    @objc func checkWrongOrRight(_ textField: UITextField) {
        // ??????????????? I thought that a logic of app could be here        
        if textLabel.text == resultTextLabel.text {
            textLabel.textColor = .green
        } else {
            textLabel.textColor = .red
        }
    }
    func setUpConstraints() {   
        textLabel.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 20).isActive = true
        textLabel.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -20).isActive = true
        textLabel.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100).isActive = true
        resultTextLabel.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 20).isActive = true
        resultTextLabel.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: -20).isActive = true
        resultTextLabel.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 500).isActive = true        
    }
}

So how can I compare characters in UILabel and in UITextField?


Solution

  • One way to do this is to get the length of the typed text and compare that to the substring of the expected text of the same length:

    @objc func checkWrongOrRight(_ textField: UITextField) {
            guard let text = textLabel.text,
                  let input = textField.text
            else {
                textLabel.textColor = .red
                return
            }
    
            if  input == text.prefix(input.count) {
                textLabel.textColor = .green
            } else {
                textLabel.textColor = .red
            }
        }
    

    Edit

    Since the actual question is about colouring individual characters depending on whether they match or not:

    You can use Attributed strings for this, getting the ranges of characters that in incorrect and applying the red colour as an attribute to these ranges:

    Define this helper function in your view controller

    // helper function that returns an attributed string to display
    func displayString(input: String?, expected: String?) -> NSAttributedString {
            guard let input = input,
                  let expected = expected
            else {
                return NSAttributedString(string: "")
            }
            // Get an array of NSRange objects of incorrect characters
            let errorRanges = zip((0...), zip(input, expected).map(==)).filter { !$1 }.map { NSRange(location: $0.0, length: 1) }
    
            // Set the default colour
            let attString = NSMutableAttributedString(string: input, attributes: [.foregroundColor: UIColor.green])
            // Set the colour for incorrect characters to red
            errorRanges.forEach { range in
                attString.addAttribute(.foregroundColor, value: UIColor.red, range: range)
            }
    
            return attString
        }
    

    And you can use it as

    @objc func checkWrongOrRight(_ textField: UITextField) {
            textField.attributedText = displayString(input: textField.text, expected: textLabel.text)
        }
    

    This colours the incorrect characters.enter image description here

    There are optimisations that can be made - such as converting the current 1 character length ranges to a single range where consecutive characters are incorrect.