Get range of parsed input #69
-
Hi, I am struggling to find a way to get the range of my parsed input and I am not sure whether this is something which would be useful to this library. For example consider the following use case: Here is a simple example: final class IngredientParser {
func parse(_ ingredients: [String]) -> [Ingredient] {
return ingredients.compactMap {
parseLine($0.trimmingCharacters(in: .whitespacesAndNewlines))
}
}
func parse(_ ingredientsInput: String) -> [Ingredient] {
return parse(ingredientsInput.split(separator: "\n").map { String($0) })
}
private func parseLine(_ ingredientsInput: String) -> Ingredient? {
let amount: AnyParser<Substring.UTF8View, Int> = Int.parser()
.eraseToAnyParser()
let unit: AnyParser<Substring.UTF8View, Unit> = "gram".utf8.map { Unit.gram }.eraseToAnyParser()
let line = Optional.parser(of: amount)
.skip(Whitespace())
.take(Optional.parser(of: unit))
.skip(Whitespace())
.take(Rest())
.map { result -> Ingredient in
return Ingredient(amount: result.0, unit: result.1, name: result.2)
}
var input = ingredientsInput[...].utf8
return line.parse(&input)
}
} Would it be possible to get the parsed range of f.e the Int.parser() from parsing the amount? |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 1 reply
-
Hi @dehlen, One way to capture the range of a parsed result is by introducing a new operator that captures it. Here's something @mbrandonw and I sketched out: extension Parser where Input: Collection {
func withRange() -> AnyParser<Input, (output: Output, range: Range<Input.Index>)> {
.init { input in
let startIndex = input.startIndex
guard let output = self.parse(&input)
else { return nil }
let endIndex = input.startIndex
return (output, startIndex ..< endIndex)
}
}
} With that defined, you can get the range from let parser = Int.parser().withRange()
let input = "123 Hello"[...].utf8
let (output, range) = parser.parse(&input)!
XCTAssertEqual(123, output)
XCTAssertEqual(3, input.distance(from: range.lowerBound, to: range.upperBound)) Hope this helps! I'm going to convert this to a discussion, since it's not a bug with the library. |
Beta Was this translation helpful? Give feedback.
Hi @dehlen,
One way to capture the range of a parsed result is by introducing a new operator that captures it. Here's something @mbrandonw and I sketched out:
With that defined, you can get the range from
Int.parser()
by tacking onwithRange()
: