Home > database >  Extracting optional version components with JQ regex
Extracting optional version components with JQ regex

Time:01-16

I'm trying to define a regex to extract versioning information from strings that may have been formatted with different versioning schemes.

Examples:

v2.234324
4.5.0
v1.1.0-bar
v2.3-foo
V1
FEE-v1.0.2-fuu

I can "generalize" these versioning schemes by considering the following constituents:

  • An optional compatibility prefix
  • An optional v or V
  • Up to 3 version components, but at least 1: major, (minor), (patch)
  • An optional compatibility suffix

I'm currently using the following regex:

(?:(?<compat_prefix>^.*)-)?[vV]?(?<version>(?<major>\\d )(?:\\.(?<minor>\\d ))?(?:\\.(?<patch>\\d )?))(?:-(?<compat_suffix>.*$))?

Example:

$ echo '[{"version":"v1.2.3"},{"version":"v1.2"}]' | jq '.[].version | capture("(?:(?<compat_prefix>^.*)-)?[vV]?(?<version>(?<major>\\d )(?:\\.(?<minor>\\d ))?(?:\\.(?<patch>\\d )?))(?:-(?<compat_suffix>.*$))?")'

{
  "compat_prefix": null,
  "version": "1.2.3",
  "major": "1",
  "minor": "2",
  "patch": "3",
  "compat_suffix": null
}
{
  "compat_prefix": null,
  "version": "1.2",
  "major": "1",
  "minor": null,
  "patch": "2",
  "compat_suffix": null
}

And this works mostly fine for my purposes.

But I'd like minor to take precedence over patch when there are only two version components.

I've tried to use non greedy match on the patch capture group ?? without success:

$ echo '[{"version":"foo-v1.2"}]' | jq '.[].version | capture("(?:(?<compat_prefix>^.*)-)?[vV]?(?<version>(?<major>\\d )(?:\\.(?<minor>\\d ))?(?:\\.(?<patch>\\d )??))(?:-(?<compat_suffix>.*$))?")'

{
  "compat_prefix": "foo",
  "version": "1.",
  "major": "1",
  "minor": null,
  "patch": null,
  "compat_suffix": null
}

I've also attempted to use possesive quantifier ? in the minor capturing group with similar result:

$ echo '[{"version":"foo-v1.2"}]' | jq '.[].version | capture("(?:(?<compat_prefix>^.*)-)?[vV]?(?<version>(?<major>\\d )(?:\\.(?<minor>\\d ))? (?:\\.(?<patch>\\d )?))(?:-(?<compat_suffix>.*$))?")'

# Nothing is returned

I would appreciate help to understand why my attempts aren't working and what to do instead.

CodePudding user response:

Try grouping minor and patch together like this:

capture("^((?<compat_prefix>.*)-)?[Vv]?(?<version>(?<major>\\d )(\\.(?<minor>\\d )(\\.(?<patch>\\d ))?)?)(-(?<compat_suffix>.*))?$")

Online demo

  • Related