How to replace a string pattern in a string with a unicode character

Viewed 21

I have a string "This is a symbol U+0202 and so is this U+023B" that I want to replace every occurrence of the string pattern "U+XXXX" with \u{XXXX}. For example, an extension to String that does that:

extension String {
  var withConvertedUnicodeSymbols : String { ... }
}

Example:

var string0 = "This is a symbol U+0202 and so is this U+023B"
var string1 = string0.withConvertedUnicodeSymbols
// string1 = "This is a symbol \u{0202} and so is this \u{023B}"
print(string1)
// prints: This is a symbol Ȃ and so is this Ȼ
1 Answers

Works but maybe there's a better answer.

extension Substring {
  var asString : String { String(self) }
}

extension String {
    func index(at: Int) -> Index {
        index(startIndex, offsetBy: at)
    }
    
    func indexDistance(to: Index) -> IndexDistance {
        distance(from: startIndex, to: to)
    }

    func substring(from: Int) -> Substring {
        if from < 0 {
            return self[max(0, length + from) ..< length]
        }
        return self[min(from, length) ..< length]
    }

    func replacing(regex: String, with: (Substring)->String) -> String {
        var r = ""
        var i = 0
        while let range = self.range(of: regex, options: .regularExpression, range: index(at: i)..<endIndex, locale: nil) {
            r += self.substring(from: UInt(i), to: indexDistance(to: range.lowerBound).magnitude)
            i = indexDistance(to: range.upperBound)
            r += with(self[range])
        }
        if index(at: i) < endIndex {
            r += self.substring(from: i)
        }
        return r
    }

    var withConvertedUnicodeSymbols : String {
        replacing(regex: "U\\+....", with: { s in
            let S = s.asString.split("U+")
            if S.count == 2, let N = UInt32(S[1], radix: 16) {
                let U = Unicode.Scalar(N)
                return U?.escaped(asASCII: false) ?? s.asString
            }
            return s.asString
        })
    }
}
Related