@Gereon's answer is one way to skin the cat. Here's another:
let s = "\u{1B}[2K\u{1B}[1G\u{1B}[32msuccess\u{1B}[39m Checking for changed pages - 0.000s"
guard let r = s.range(of: "Checking for changed pages") else {
fatalError("Insert code for what to do if the substring isn't found")
}
let cleaned = "success " + String(s[r.lowerBound...])
Here I just literally insert the "success". But if you really need to verify that it's in the string, that can be done too.
guard let r = s.range(of: "Checking for changed pages"), s.contains("success")
else
{
fatalError("Insert code for what to do if the substring isn't found")
}
To solve the more general problem of removing ANSI escape sequences, you'll need to parse them. Neither my simple solution, nor the regex solution will do it. You'll need to explicitly look for the possible valid codes that follow the escapes.
let escapeSequences: [String] =
[/* list of escape sequnces */
"[2K", "[1G", "[32m", "[39m", // etc...
]
let escapeChar = Character("\u{1B}")
var result = ""
var i = s.startIndex
outer: while i != s.endIndex
{
if s[i] == escapeChar
{
i = s.index(after: i)
for sequence in escapeSequences {
if s[i...].hasPrefix(sequence) {
i = s.index(i, offsetBy: sequence.distance(from: sequence.startIndex, to: sequence.endIndex))
continue outer
}
}
}
else { result.append(s[i]) }
i = s.index(after: i)
}
print(result)
The thing is, I think ANSI escape sequences can be combined in interesting ways so that what would be multiple escapes can be merged into a single one in some cases. So it can be more complex than just the simple parser I presented.