Merging parsers that consume entire input #84
-
Hello! I have multiple parsers that consume the entire input (using Rest() parser) and I can't find a nice way to merge them. To give my concrete example, the string I'm trying to parse is a connection string for Azure Notifications Hub. let input = "Endpoint=sb://organization-name.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=3252389randomCharacters43242380=09=/="
// The parsers:
let endpointInputParser = StartsWith("Endpoint=sb")
.flatMap( { Always("https") } )
.take(Rest())
.map { $0 + $1 } // replace Endpoint=sb with https
let sasKeyNameParser = StartsWith("SharedAccessKeyName=")
.take(Rest())
let sasKeyValueParser = StartsWith("SharedAccessKey=")
.take(Rest())
// How to I merge them?
Many(Prefix(minLength: 1) { $0 != ";" }, separator: ";")
.flatMap { components -> AnyParser<Substring, (Substring, Substring, Substring)> in
guard components.count == 3 else {
return Fail().eraseToAnyParser()
}
return Always((components[0], components[1], components[2])).eraseToAnyParser()
}
.map({ endpoint, keyName, keyValue in
let endppointOutput = endpointInputParser
.parse(endpoint)
// ... the same for all parsers, manually merge the results, but it's error prone
}) The solutions I though about was either implementing a MergeN parsers that would act similarly to TakeN, but it seems like there should be an easier way. Another solution would be to make each parser aware of this separator and to read until they reach it instead of using Rest(), but I feel like they shouldn't know about that. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments 3 replies
-
My (naive) approach would be to just let input = "Endpoint=sb://organization-name.servicebus.windows.net/;SharedAccessKeyName=DefaultListenSharedAccessSignature;SharedAccessKey=3252389randomCharacters43242380=09=/="
let endpointParser = StartsWith("Endpoint=sb")
.take(Rest())
.map { "https" + $0 }
let sasKeyNameParser = StartsWith("SharedAccessKeyName=")
.take(Rest())
let sasKeyValueParser = StartsWith("SharedAccessKey=")
.take(Rest())
let parser = PrefixUpTo(";")
.pipe(endpointParser)
.skip(";")
.take(
PrefixUpTo(";")
.pipe(sasKeyNameParser)
.skip(";")
)
.take(
sasKeyValueParser
) This ensures your |
Beta Was this translation helpful? Give feedback.
-
I think Because you preferably don't want the These strict parsers will combine fluently when building the final parser: |
Beta Was this translation helpful? Give feedback.
My (naive) approach would be to just
pipe
the component parsers down a couple ofPrefixUpTo
parsers like this: