-
Hi, I'm trying to parse console output and extract the text attributes. For a simple line, it's correct but when I have multiple attributes it doesn't work properly in all cases. The issue is with BTW I did find another issue with the library, when I try to parse text that contains invisible characters like \u{1B} the error show Thanks, A color is like this let terminalAttribute = Parse(TerminalColor.init) {
"["
Int.parser()
Optionally {
";"
Int.parser()
}
"m"
} In one line of the log, there are multiple sections of text with optional text attributes and what I expect at the end is a public struct ParsedLog: CustomStringConvertible {
var text: String
var color: TerminalColor?
} Console log example(without all the invisible characters)
Output
The full exemple. The issue is in import Foundation
import Parsing
public struct ParsedLog: CustomStringConvertible {
var text: String
var color: TerminalColor?
public var description: String {
var out = "text: \(text)"
if let color = color {
out += ", attributes: \(color.description)"
}
return out
}
public init(string: String, color: TerminalColor? = nil) {
self.text = string
self.color = color
}
public init(substring: Substring, color: TerminalColor? = nil) {
self.text = String(substring)
self.color = color
}
}
public let mainParser = Many {
OneOf {
textWithAttributes
textWithoutAttributes
}
}
// MARK: Parser Internal
let textWithAttributes = Parse {
terminalAttribute
PrefixUpTo("[").map(String.init)
Optionally { endColor }
}.map { ParsedLog(string: $0.1, color: $0.0) }
let textWithoutAttributes = Parse {
Not { terminalAttribute }
OneOf {
PrefixUpTo("[").map(String.init)
Rest().map(String.init)
}
}.map { ParsedLog(string: $0) }
let terminalAttribute = Parse(TerminalColor.init) {
"["
Int.parser()
Optionally {
";"
Int.parser()
}
"m"
}
let endColor = Skip {
"[0m"
} |
Beta Was this translation helpful? Give feedback.
Replies: 4 comments 2 replies
-
After more investigation I did find a way around it. I did remplace I did this import Foundation
import Parsing
extension String: Error {}
public struct PrefixUntil<Input: Collection, Upstream: Parser>: Parser where Input.SubSequence == Input, Upstream.Input == Input {
public let upstream: Upstream
@inlinable
public init(@ParserBuilder _ build: () -> Upstream) {
self.upstream = build()
}
@inlinable
public func parse(_ input: inout Input) throws -> Input {
guard !input.isEmpty else { throw "a non-empty input(\(input))" }
let originalInput = input
var lastIndex = input.startIndex
var out = try? self.upstream.parse(&input)
while out == nil && lastIndex != input.endIndex {
input.removeFirst()
lastIndex = input.startIndex
out = try? self.upstream.parse(&input)
}
return originalInput[..<lastIndex]
}
}
extension PrefixUntil where Input == Substring {
@_disfavoredOverload
@inlinable
public init(@ParserBuilder _ build: () -> Upstream) {
self.upstream = build()
}
}
extension PrefixUntil where Input == Substring.UTF8View {
@_disfavoredOverload
@inlinable
public init(@ParserBuilder _ build: () -> Upstream) {
self.upstream = build()
}
} |
Beta Was this translation helpful? Give feedback.
-
I'm having a infinite loop with this refined version. 🤔 I was hoping that the
import Foundation
import Parsing
// input: [36mINFO[0m[08:45:33] [33;1mci runs in Secret Filtering mode[0m
public let mainParser = Many(1...) {
textWithAttributes
}
// MARK: Parser Internal
let textWithAttributes = Parse(ParsedLog.init(color:string:)) {
Optionally { terminalFontModifier }
OneOf {
End().map { Optional<String>.none }
Optionally { PrefixUntil { terminalFontModifier } .map(String.init) }
}
}
let terminalFontModifier = Parse(TerminalAttribute.init) {
"["
Int.parser()
Optionally {
";"
Int.parser()
}
"m"
} |
Beta Was this translation helpful? Give feedback.
-
I just have to add |
Beta Was this translation helpful? Give feedback.
-
I have open a PR to upstream this parser fixed and faster #229 |
Beta Was this translation helpful? Give feedback.
I just have to add
Peek { Prefix<Substring>(1) }
before the other optional parser in order to be sure that the input wasn't empty.