How to match overlapping key:value declarations with a regular expression?

Viewed 39

The problem statement:

  • The query must be in the format field:value.

  • The value can contain any number of words, e.g. field:my value.

  • The value can also be a regular expression. To enforce this, use two colons e.g. field::value.*.

  • Finally, you can specify any number of field/value pairs. For example, field1:value 1 field2::value2.

The problem is, I can't figure out how to match 'value 1' reliably if field2 does or doesn't exist.

What I've got so far:

r'(\S+?):'  # match field
r'(:?)'     # capture extra : if regex value
r'(.+?(?=\s\S+:))|(.+(?!\s\S+:))'  # match value, but don't capture field2 if it exists

I'm struggling with the last part. (.+?(?=\s\S+:)) does what I want if field2 exists, but this won't work if field2 doesn't exist.

The idea is then to call matches = re.findall(QUERY_REGEX, query) to get all the matches. So, for the final example given, the output should be [('field1', '', 'value 1'), ('field2', ':', 'value2')]

1 Answers

You may use the following pattern:

(\S+)::?(.+?)(?=\s\S+:|$)

Demo.

This has two capturing groups; one for the key and one for the value. You may add more groups if needed.

The main change to the Lookahead is to check if the "value" is either followed by another key or it's at the end of the line.

Related