1
I’m having difficulties to replace different templates in a text, my Regex returns more than one need to replace according to the variable value strReplaced
Follows code:
import Foundation
let texto = "Bem-[sexo:vindo,vinda] à aventura de viver a vida sendo você [sexo:mesmo,mesma], a partir de um espaço de liberdade, de escolhas e de possibilidades!"
protocol FilterTagProtocol {
var pattern: String { get }
}
struct FilterTagManager {
enum FiltersTexts: String, CaseIterable, FilterTagProtocol {
case gender = "\\[sexo:([^]]*)\\]"
case name = "\\[nome\\]"
var pattern: String {
return self.rawValue
}
}
func replaceGender(text: String) -> String {
let split = text.split(separator: ",")
if split.count > 1 {
let male = String(split[0])
let female = String(split[1])
if split.count != 2 || male.count == 0 || female.count == 0 {
return ""
} else {
return male
}
}
return text
}
private func replaceName(text: String) -> String {
return "Mike"
}
func applyFilter(text: String, filter: FiltersTexts) -> String {
do {
let regEx = try NSRegularExpression(pattern: filter.pattern, options: [.anchorsMatchLines])
let matches = regEx.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
if matches.count > 0 {
let rangeAt = filter == .name ? 0 : 1
let substring = (text as NSString).substring(with: (matches.first?.range(at: rangeAt))!)
return substring
}
} catch {
print("ERROR applyFilter: ", error.localizedDescription)
return text
}
return text
}
func replace(text: String, filter: FiltersTexts) -> String {
let textFiltered = applyFilter(text: text, filter: filter)
switch filter {
case .gender:
return replaceGender(text: textFiltered)
case .name:
return replaceName(text: textFiltered)
}
}
func replaceText(from text: String, type: FiltersTexts) -> (newString: String, range: NSRange)? {
do {
let regEx = try NSRegularExpression(pattern: type.pattern, options: [])
let matches = regEx.matches(in: text, options: [], range: NSRange(location: 0, length: text.utf16.count))
for match in matches as [NSTextCheckingResult] {
let textNS = (text as NSString)
let strReplaced = replace(text: text, filter: type)
let innerContentBlock = textNS.substring(with: match.range)
let newString = text.replacingOccurrences(of: innerContentBlock, with: strReplaced)
return (newString: newString, range: match.range)
}
} catch {
print(error.localizedDescription)
return nil
}
return nil
}
func replaceTexts(from text: String, type: FiltersTexts) -> String? {
let templates = matches(for: type.pattern, in: text)
var newText = text
for template in templates {
let strReplaced = replace(text: template, filter: type)
if newText.contains(template) {
newText = newText.replacingOccurrences(of: template, with: strReplaced)
}
}
return newText
}
func matches(for regex: String, in text: String) -> [String] {
do {
let regex = try NSRegularExpression(pattern: regex)
let results = regex.matches(in: text,
range: NSRange(text.startIndex..., in: text))
let finalResult = results.map {
String(text[Range($0.range, in: text)!])
}
return finalResult
} catch let error {
print("invalid regex: \(error.localizedDescription)")
return []
}
}
func normalizeTexts(contentBlock: String) -> String {
var brokenText = contentBlock
for filter in FiltersTexts.allCases {
if let filterBlock = replaceTexts(from: brokenText, type: filter) {
brokenText = filterBlock
}
}
return brokenText
}
}
let filter = FilterTagManager()
let newText = filter.normalizeTexts(contentBlock: texto)
print(newText)
the same is also in GIST: https://gist.github.com/micheltlutz/47f7ddce882be31be7fafa33c594f819
Does anyone have any better suggestions?
Corrected as follows

func replaceTexts(from text: String, type: FiltersTexts) -> String? {
 let templates = matches(for: type.pattern, in: text)
 var newText = text
 for template in templates {
 let strReplaced = replace(text: template, filter: type)
 if newText.contains(template) {
 newText = newText.replacingOccurrences(of: template, with: strReplaced)
 }
 }
 return newText
 }

If someone has a better shape– Michel Anderson Lütz Teixeira