0

Is it possible to just replace a specific text's value in a file python? The below code replaces the string however I could'nt find a way to replace only the project_id or project_name's value.

import re 

def replace():
    with open("/Users/test/file.txt", "r") as sources:
        lines = sources.readlines()
    with open("/Users/test/file.txt", "w") as sources:
        for line in lines:
            sources.write(re.sub(r"Settings", 'Project_settings', line))

    
replace()

file.txt

Settings
######################
project_id = "468324678997"
project_name = "test"

output:

Project_settings
######################
project_id = "468324678997"
project_name = "test"

I would like to replace project_name's value to "abc"

Desired output: file.txt

Settings
######################
project_id = "468324678997"
project_name = "abc"
nad87563
  • 3,672
  • 7
  • 32
  • 54
  • Can you add your desired output? Do you want to replace the word "test" in your example file? – Iain Shelvington Aug 06 '21 at 03:52
  • What happened when you tried running the code, and how is that different from your desired result? – Karl Knechtel Aug 06 '21 at 04:00
  • In your own words, where you have `re.sub(r'^# project_name', 'abc', line)`, what *exactly* do you think that means? What source are you using to learn how to use regular expressions, and what happened when you tried following a tutorial? – Karl Knechtel Aug 06 '21 at 04:01
  • Updated the question, i'm using re.sub to replace the string and it works. however i'm having issues to replace only the variable value using regex. – nad87563 Aug 06 '21 at 04:26
  • Perhaps that's because there is no Python variable named "project_name." That's a piece of text that you are writing to a file, not the name of a variable in a Python script. – Paul Cornelius Aug 06 '21 at 04:28
  • 1
    Why does your expected output have `Settings` and your code has `Project_settings`? – OneCricketeer Aug 06 '21 at 04:38
  • Also, what do you expect to happen if you had a line like `project_name = "Settings Test"`? – OneCricketeer Aug 06 '21 at 04:39
  • Settings is not going to occur anywhere in the file. Why does your expected output have Settings and your code has Project_settings - its just an example code for replacing a specific string in a file. – nad87563 Aug 06 '21 at 04:52

2 Answers2

2

I suggest using a dictionary of config overrides, not regex

This way, you are not accidentally replacing all matching text

def replace(file, overrides):
    with open(file, "r") as sources:
        lines = sources.readlines()
    with open(file, "w") as sources:
        # skip the header rows
        next(lines)
        next(lines)
        for line in lines:
            config_key = line.split(' = ')[0]
            if config_key in overrides:
                sources.write('{} = {}\n'.format(config_key, overrides[config_key]))

overrides = {
  'project_name': 'abc'
}
replace("/Users/test/file.txt", overrides)

There are likely better Python libraries that can read property files and allow you to override specific values

OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • 1
    IMO, that isnt really needed because if the headers are removed you can just `import config.py` – OneCricketeer Aug 06 '21 at 05:20
  • So, we agree in that point: once recognized the _major pattern_ of given file-format (and ignoring headers) you can just use existing libs to parse & modify. – hc_dev Aug 06 '21 at 11:31
1

Automate the text-editor's regex-replace

My recipe for replacing each matching line in an arbitrary formatted text-file.

As arguments to re.sub you could use a pair of regular-expressions: pattern-to-match and replacement, like regex-tuple (r'^Settings', r'Project_settings').

The data structure to store these could be a list of tuples (pairs), like replacements.

import re

replacements = [
    ('^Settings', 'Project_settings'),
    (r'^project_name = "(.*)"', r'project_name = "abc"'), # simply replaces with fixed value
    (r'^project_id = "(.*)"', r'project_id = "P-\1"')  # copies in the found group 1 at \1
]


def replace():
    lines = []
    with open("project_properties.cfg", "r") as config:
        for line in config.readlines():
            for pair in replacements:  # apply each replacement that matches line
                line = re.sub(pair[0], pair[1], line)  # substitute found pattern with replacement
            lines.append(line)  # add each read line to the buffer (if changed or not)

    with open("project_properties_.cfg", "w") as config: # Note: used a new filename
        config.writelines(lines)


replace()

Will result in desired output (plus inserting-replacement at project_id):

Project_settings
######################
project_id = "P-468324678997"
project_name = "abc"

Parsing and Updating with existing libs

As OneCricketeer's answer suggests:

When you manage to ignore the header, you will recognize strong similarity (i.e. key = value representation) to at least two common config-file formats:

This would allow you to research and find existing libraries, like Python's built-in configparser:

hc_dev
  • 8,389
  • 1
  • 26
  • 38