Best way to do a regular expressions substitution

Viewed 50

I have the following code to change the version string inside the provider "aws" block. using re.search() and re.sub(). Is it possible to do it with just re.sub()?

def process(p, provider, version):
  g = re.search(r'provider\s+"%s"\s+\{[\s\S]*version\s+=\s+"(.*)"[\s\S]*\}' % provider, p).group(1)
  return re.sub(r'%s' % g, '~> ' + version, p)

p = """
provider "aws" {
  region  = var.region
  version = "~> 2.59"

  assume_role {
    role_arn = "tes_role"
  }
}
"""

r = process(p, "aws", "2.61")
print(r)
1 Answers

Yes, it is possible, you need to use a capturing group and an unambiguous replacement backreference when using re.sub, and you need to alter the pattern a bit:

def process(p, provider, version):
  return re.sub(r'(provider\s+"{}"\s+{{[\s\S]*?version\s+=\s+"~>\s*)[^"]*'.format(provider),
    r'\g<1>{}'.format(version),
    p)

See the Python demo

The pattern is

(provider\s+"aws"\s+{[\s\S]*?version\s+=\s+"~>\s*)[^"]*

And the replacement is \g<1>2.61. See the regex demo.

Details

  • (provider\s+"aws"\s+{[\s\S]*version\s+=\s+"~>\s*) - Group 1 (\g<1> is the backreference to the group value (note you can't use \1 because the next char is a digit!)):
    • provider - a word
    • \s+ - 1+ whitespaces
    • "aws" - "aws"
    • \s+ - 1+ whitespaces
    • { - a { char (in a format string, it must be doubled)
    • [\s\S]* - 0+ chars, as few as possible
    • version - a word version
    • \s+=\s+ - a = char enclosed with 1+ whitespaces
    • "~> - a "~> substring
    • \s* - 0+ whitespaces
  • [^"]* - 0+ chars other than "
Related