简体   繁体   中英

How do I alter an existing text file to add new data after a specific line using Python

So I am looking to create a script to make a mod for a game using Python. The script will need to copy all files from a directory to another directory, then alter those files to add a new attribute after a specific line. The issue I am having is that this game uses custom coding based on json formatting in a txt file. I know how to do most of this, however, adding the new data is not something I can get to work.

My end goal will be to be able to do this to any file, so other mod authors can use it to add the data to their mods without needing to do it manually. I also want to try to make this script do more advanced things, but that is another goal that can wait till I get this bit working.

Sample data: The line I need to add is position_priority = ### . The ### will be different based on what the building does (building categories).

Sample code I need to alter:

building_name_number = {
    base_build_time = 60
    base_cap_amount = 1
    
    category = pop_assembly
   
    <more code>
}

I need to put the new data just after building_name_number , however this exact name will be unique, the only thing that will always be the same is that it will start with building . So regex is what I have been trying to use, but I have never dealt with regex so I cant get it to work.

My Current code:

if testingenabled:
    workingdir = R"E:/Illusives-Mods/Stellaris/Building Sorting"
    pattern = "^building_"
    Usortingindex = sortingindex["sorting_pop_assembly"]
    print(f"Testing Perameters: Index: {Usortingindex}, Version: {__VERSION__}, Working DIR: {workingdir}")
    # os.chdir(stellaris_buildings_path)
    os.chdir(workingdir)
    for file in os.listdir(workingdir):

        if fnmatch.fnmatch(file, "*.txt"):
            
            print("File found")

            with open(file, "r+", encoding="utf-8") as openfiledata:
                alllines = openfiledata.read()
                for line in alllines:
                    if line == re.match(r'(^building_)', line, re.M):
                        print("found match")
                        # print(f"{sorting_attrib}{Usortingindex}")
                        # print("position_priority = 200")
                        openfiledata.write("\n" + sorting_attrib + Usortingindex + "\n")

            break

I am not getting any errors with this code. But it doesnt work I am using Python 3.9.6 .

EDIT: This code is before the script

    allow = {
        hidden_trigger = {
            OR = {
                owner = { is_ai = no }
                NAND = {
                    free_district_slots = 0
                    free_building_slots <= 1
                    free_housing <= 0
                    free_jobs <= 0
                }
            }
        }
    }

This is after

        allow = {
            hidden_trigger = {
                OR = {
                    owner = {
                        is_ai = false
                    }
                    NAND = {
                        free_district_slots = 0
                        free_building_slots = {
                            value = 1
                            operand = <=
                        }
                        free_housing = {
                            value = 0
                            operand = <=
                        }
                        free_jobs = {
                            value = 0
                            operand = <=
                        }
                    }
                }
            }
        }

The output must be the same as the input, at least in terms of the operators

If you would keep it as JSON then you could read all to Python (to get ti as dictionary), search and add items in dictionary, and write back to JSON new dictionary.

text = '''{
"building_name_number": {
    "base_build_time": 60,
    "base_cap_amount": 1,
    "category": "pop_assembly"
},
"building_other": {}
}'''

import json

data = json.loads(text)

for key in data.keys():
    if key.startswith('building_'):
        data[key]["position_priority"] = 'some_value'
        
print(json.dumps(data, indent=4))

Result:

{
    "building_name_number": {
        "base_build_time": 60,
        "base_cap_amount": 1,
        "category": "pop_assembly",
        "position_priority": "some_value"
    },
    "building_other": {
        "position_priority": "some_value"
    }
}

I found module paradox-reader which can convert this file format to JSON file.

Using code from file paradoxReader.py I created example which can convert string to Python dictionary, add some value and convert to something similar to original file. But this may need to add more code in encode()

import json
import re

def decode(data):#, no_json):

    data = re.sub(r'#.*', '', data) # Remove comments
    data = re.sub(r'(?<=^[^\"\n])*(?<=[0-9\.\-a-zA-Z])+(\s)(?=[0-9\.\-a-zA-Z])+(?=[^\"\n]*$)', '\n', data, flags=re.MULTILINE) # Seperate one line lists
    data = re.sub(r'[\t ]', '', data) # Remove tabs and spaces

    definitions = re.findall(r'(@\w+)=(.+)', data) # replace @variables with value

    if definitions:
        for definition in definitions:
            data = re.sub(r'^@.+', '', data, flags=re.MULTILINE)
            data = re.sub(definition[0], definition[1], data)

    data = re.sub(r'\n{2,}', '\n', data) # Remove excessive new lines
    data = re.sub(r'\n', '', data, count=1)  # Remove the first new line
    data = re.sub(r'{(?=\w)', '{\n', data) # reformat one-liners
    data = re.sub(r'(?<=\w)}', '\n}', data) # reformat one-liners
    data = re.sub(r'^[\w-]+(?=[\=\n><])', r'"\g<0>"', data, flags=re.MULTILINE)  # Add quotes around keys
    data = re.sub(r'([^><])=', r'\1:', data)  # Replace = with : but not >= or <=
    data = re.sub(r'(?<=:)(?!-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)(?!\".*\")[^{\n]+', r'"\g<0>"', data)  # Add quotes around string values
    data = re.sub(r':"yes"', ':true', data) # Replace yes with true
    data = re.sub(r':"no"', ':false', data)  # Replace no with false
    data = re.sub(r'([<>]=?)(.+)', r':{"value":\g<2>,"operand":"\g<1>"}', data) # Handle < > >= <=
    data = re.sub(r'(?<![:{])\n(?!}|$)', ',', data)  # Add commas
    data = re.sub(r'\s', '', data) # remove all white space
    data = re.sub(r'{(("[a-zA-Z_]+")+)}', r'[\g<1>]', data) # make lists
    data = re.sub(r'""', r'","', data) # Add commas to lists
    data = re.sub(r'{("\w+"(,"\w+")*)}', r'[\g<1>]', data)
    data = re.sub(r'((\"hsv\")({\d\.\d{1,3}(,\d\.\d{1,3}){2}})),', r'{\g<2>:\g<3>},', data) # fix hsv objects
    data = re.sub(r':{([^}{:]*)}', r':[\1]', data) # if there's no : between list elements need to replace {} with []
    data = re.sub(r'\[(\w+)\]', r'"\g<1>"', data)
    data = re.sub(r'\",:{', '":{', data) # Fix user_empire_designs
    data = '{' + data + '}'

    return json.loads(data)

def encode(data):
    text = json.dumps(data, indent=4)
    text = text[2:-2]
    text = text.replace('"', '').replace(':', ' =').replace(',', '')
    return text

# ----------

text = '''building_name_number = {
    base_build_time = 60
    base_cap_amount = 1
    
    category = pop_assembly
}'''

data = decode(text)
data['building_name_number']['new_item'] = 123

text = encode(data)
print(text)

Result:

    building_name_number = {
        base_build_time = 60
        base_cap_amount = 1
        category = pop_assembly
        new_item = 123
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM