this repo has no description
1import Foundation
2
3public enum TextParsing {
4 /// Removes ANSI escape sequences so regex parsing works on colored terminal output.
5 public static func stripANSICodes(_ text: String) -> String {
6 // CSI sequences: ESC [ ... ending in 0x40–0x7E
7 let pattern = #"\u001B\[[0-?]*[ -/]*[@-~]"#
8 guard let regex = try? NSRegularExpression(pattern: pattern, options: []) else { return text }
9 let range = NSRange(text.startIndex..<text.endIndex, in: text)
10 return regex.stringByReplacingMatches(in: text, options: [], range: range, withTemplate: "")
11 }
12
13 public static func firstNumber(pattern: String, text: String) -> Double? {
14 guard let regex = try? NSRegularExpression(pattern: pattern, options: [.caseInsensitive]) else { return nil }
15 let range = NSRange(text.startIndex..<text.endIndex, in: text)
16 guard let match = regex.firstMatch(in: text, options: [], range: range),
17 match.numberOfRanges >= 2,
18 let r = Range(match.range(at: 1), in: text) else { return nil }
19 let raw = text[r].replacingOccurrences(of: ",", with: "")
20 return Double(raw)
21 }
22
23 public static func firstInt(pattern: String, text: String) -> Int? {
24 guard let v = firstNumber(pattern: pattern, text: text) else { return nil }
25 return Int(v)
26 }
27
28 public static func firstLine(matching pattern: String, text: String) -> String? {
29 guard let regex = try? NSRegularExpression(pattern: pattern, options: [.caseInsensitive]) else { return nil }
30 let range = NSRange(text.startIndex..<text.endIndex, in: text)
31 guard let match = regex.firstMatch(in: text, options: [], range: range),
32 let r = Range(match.range(at: 0), in: text) else { return nil }
33 return String(text[r])
34 }
35
36 public static func percentLeft(fromLine line: String) -> Int? {
37 guard let pct = firstInt(pattern: #"([0-9]{1,3})%\s+left"#, text: line) else { return nil }
38 return pct
39 }
40
41 public static func resetString(fromLine line: String) -> String? {
42 guard let regex = try? NSRegularExpression(pattern: #"resets?\s+(.+)"#, options: [.caseInsensitive]) else {
43 return nil
44 }
45 let range = NSRange(line.startIndex..<line.endIndex, in: line)
46 guard let match = regex.firstMatch(in: line, options: [], range: range),
47 match.numberOfRanges >= 2,
48 let r = Range(match.range(at: 1), in: line)
49 else {
50 return nil
51 }
52 // Return the tail text only (drop the "resets" prefix).
53 return String(line[r]).trimmingCharacters(in: .whitespacesAndNewlines)
54 }
55}