A plant nursery prints pot labels from one-line specs like
name="Boston fern" water=weekly light="bright, indirect"
Write parse_tags(line: str) -> dict[str, str] that turns such a line into a dict, or raises ValueError if the line is malformed.
Grammar (the only whitespace is the plain space " "):
- A line is zero or more pairs, separated by one or more spaces. Spaces before the first pair and after the last one are allowed.
- A pair is a key, then
=, then a value, with no spaces around=. - A key is one or more characters from
A-Z,a-z,0-9and_. - A value is either
- bare: one or more characters, none of which is a space,
"or=(a backslash is an ordinary character here), or - quoted:
", then any characters, then a closing". Inside the quotes,\"stands for"and\\stands for\; a backslash followed by anything else is an error. Spaces and=are ordinary characters inside quotes, and""is an empty value.
- bare: one or more characters, none of which is a space,
- Right after a value comes a space or the end of the line (so
a="x"b=1is malformed). - A key may appear only once per line.
Everything else (a missing =, an empty bare value, an unterminated quote, a bad escape, a bad key character, a duplicate key...) raises ValueError.
parse_tags('name="Boston fern" water=weekly')
# {"name": "Boston fern", "water": "weekly"}
parse_tags(r'note="say \"hi\"" path=C:\pots')
# {"note": 'say "hi"', "path": "C:\\pots"}
parse_tags(" ") # {}
parse_tags("a=1 a=2") # ValueError: duplicate key 'a'
parse_tags('a="open') # ValueError: unterminated quote
parse_tags("a= 1") # ValueError: empty value
Show hint
walk an index i through the string. Skip spaces; read a key while the character is a key character; expect =; if the next character is ", loop until the closing quote handling \ escapes, otherwise read a bare value until a space. Raise as soon as something doesn't match what you expect.