skip to Main Content

In ViewController – I have two text fields, like text field for text wihch user wants to reverse and text field for exclusions, and result-UILabel which shows the result.

In first text field user typing some text for reverse and result-UILabel shows the result of reversed text.

In the second text field, I want to make an exception for letters which shouldn’t be reversed in result-UILabel. They should be untouchable in the word of the reverse at the time of reversing the text from the first field and should remain in their places.

The model function is in another swift file in another class.


Model function:

import Foundation

class ReverseWords {

public func reverse(textField: String) -> String {
    
    if textField.isEmpty {
        return ""
    }
    
    return textField.trimmingCharacters(in: .whitespacesAndNewlines)
        .components(separatedBy: " ")
        .map { String ( $0.reversed() ) }
        .joined(separator: " ")
    }
}

Using model function for first text field in ViewController:

resultLabel.text = reverseWords.reverse(textField:
reverseTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines))

Example:

First text field (for reverse) print:

FogmEistEr

Second text field (for exclusions) letters which should be untouchable of reverse, print:

E

And result label shows:

rtsiEmgoEF

How can I implement this?

How can I call exceptionTextField in model to check his characters inside?
Actually, I don’t want to do this between classes, but I would like to look at the solution.

I think it would be better to do it in ViewController, but I got confused…

Have you any ideas, how to implement this?

2

Answers


  1. Here you can take reference for logic (It can be optimized). We can pass exclude reverse function. Rather than put this logic in the view controller I would suggest keeping the logic in ReverseWords class.

    class ReverseWords {
        
        public func reverse(textField: String, excludeWord: String) -> String {
            
            if textField.isEmpty {
                return ""
            }
            
            return textField.trimmingCharacters(in: .whitespacesAndNewlines)
                .components(separatedBy: " ")
                .map { $0 == excludeWord ? String($0) : reverseWordWithExclude(currentWord: String($0), excludeWord: excludeWord) }
                .joined(separator: " ")
        }
        
        private func reverseWordWithExclude(currentWord: String, excludeWord: String) -> String {
    
      // return direct reversed string if the exclude word not contain in string
            if !currentWord.contains(excludeWord) {
                return String(currentWord.reversed())
            }
            
            // Replace whole exception word with single space char which is never included in the current word.
            // Easy to find the current index for a single space or for a char.
            let replaceWord = currentWord.replacingOccurrences(of: excludeWord, with: " ")
            
            var reverseString = ""
            var exceptionIndexes: [Int] = []
            
            // Find the index of exclude word and reverse string without include exclude word
            replaceWord.enumerated().forEach { index, char in
                if char == " " {
                    exceptionIndexes.append(index)
                } else {
                    reverseString.insert((char), at: reverseString.startIndex)
                }
            }
            
            // Now replace single space with actual exclude word at their position.
            exceptionIndexes.forEach{ index in
                reverseString.insert(contentsOf: excludeWord, at: reverseString.index(reverseString.startIndex, offsetBy: index))
            }
            
            return reverseString
        }
    }
    
    Login or Signup to reply.
  2. I’d just make an extension on String:

    extension String {
        func reversed(omittingCharactersIn characterSet: CharacterSet) -> String {
            var reversed = reversed()
                .filter { String($0).rangeOfCharacter(from: characterSet) == nil }
            let excluded = enumerated()
                .filter { String($0.element).rangeOfCharacter(from: characterSet) != nil }
            for (i, char) in excluded {
                reversed.insert(char, at: reversed.index(reversed.startIndex, offsetBy: i))
            }
            return String(reversed)
        }
    }
    

    All this is doing is reversing all of the characters right away, but removing any characters that should not be reversed. Then it finds and maintains the indices and characters should not move. Finally, it inserts the characters that should not be reversed back to their original position.

    Usage:

    let text = "FogmEistEr"
    let omit = "E"
    print(text.reversed(omittingCharactersIn: CharacterSet(charactersIn: omit)))
    

    Prints:

    rtsiEmgoEF
    

    Here’s how I’d plug it into a viewController assuming the reversal would happen either by a button push or by the text simply changing:

    class ViewController: UIViewController {
        @IBOutlet weak var originalTextField: UITextField!
    
        @IBOutlet weak var exclusionTextField: UITextField!
    
        @IBOutlet weak var reversedLabel: UILabel!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            originalTextField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
            exclusionTextField.addTarget(self, action: #selector(textChanged(_:)), for: .editingChanged)
        }
    
        @objc func textChanged(_ sender: UITextField) {
            tryReverse()
        }
    
        @IBAction func didTapButton(_ sender: UIButton) {
            tryReverse()
        }
    
        private func tryReverse() {
    
            guard let originalText = originalTextField.trimmedTextNilIfEmpty,
                  let exclusionText = exclusionTextField.trimmedTextNilIfEmpty else {
                reversedLabel.text = ""
                return
            }
    
            reversedLabel.text = originalText.components(separatedBy: " ")
                .map {
                    $0.reversed(omittingCharactersIn: CharacterSet(charactersIn: exclusionText))
                }.joined(separator: " ")
        }
    }
    
    extension UITextField {
        var trimmedTextNilIfEmpty: String? {
            if let trimmed = text?.trimmingCharacters(in: .whitespacesAndNewlines) {
                return trimmed.isEmpty ? nil : trimmed
            }
            return nil
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search