My goal
I am parsing from a string which contains token:value
pairs into a type.
Example:
mutable struct Foo
bar
baz
qux
end
function parse(str::AbstractString)::Foo
f = Foo()
bar_pattern = r"bar:(\w*)"
baz_pattern = r"baz:(\d*)"
qux_pattern = r"qux:(\w*)"
f.bar = match(bar_pattern, s)[1]
f.baz = match(baz_pattern, s)[1]
f.qux = match(qux_pattern, s)[1]
return d
end
Problem
This works but only if the patterns are actually present. When match
can't find the pattern, it returns nothing
, which of course can't be indexed [1]
or accessed with captures
. The result is an error.
I want the fields of the returned struct to either get the matched result (the "capture") directly, or remain empty or set to nothing
, should the match be unable to find the pattern.
I could do something like this:
function safeparse(str::AbstractString)::Foo
f = Foo()
bar_pattern = r"bar:(\w*)"
baz_pattern = r"baz:(\d*)"
qux_pattern = r"qux:(\w*)"
if !isnothing(match(bar_pattern, s))
f.bar = match(bar_pattern, s)[1]
end
if !isnothing(match(baz_pattern, s))
f.baz = match(baz_pattern, s)[1]
end
if !isnothing(match(qux_pattern, s))
f.qux = match(qux_pattern, s)[1]
end
return f
end
But that approach seems ugly and becomes verbose very quick if more/new patterns are introduced.
Question
Is there a nicer but readable way to achieve this?
Preferably without combining/changing the regex patterns or too much regex magic, however I am open to that route too if it is the only nice (less verbose) way. I am of course also open to general tips.
To keep things simple, just assume that the patterns my example is looking for only appear 0 or 1 times. However if the only way to make this nicer involves writing another function like safematch
which does the check for nothing and returns the captured value or nothing, I would want that to also work with multiple matches somehow and stay a bit more general.