1

As a first step to create a "mission generator" for a flight simulator I would like to be able to extract pieces of a mission template so I can alter or delete some stuff, put it altogether again and so generate a new "mission" file. I have minimal Python skills. I don't need a working solution, but would like a direction to investigate further. Here is the challenge:

This is a (simplified) sample of the input file:

test_str = ("Group\n"
    "{\n"
    "   Name = \"Group 1\";\n"
    "   Index = 2;\n"
    "   Desc = \"Description\";\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 1\";\n"
    "       Index = 497;\n"
    "       XPos = 171568.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 204878.718;\n"
    "   }\n"
    "\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 2\";\n"
    "       Index = 321;\n"
    "       XPos = 162268.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 203478.718;\n"
    "   }\n"
    "\n"
    "}\n"
    "\n"
    "Group\n"
    "{\n"
    "   Name = \"Group 2\";\n"
    "   Index = 5;\n"
    "   Desc = \"Description\";\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 3\";\n"
    "       Index = 112;\n"
    "       XPos = 122268.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 208878.718;\n"
    "   }\n"
    "\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 4\";\n"
    "       Index = 214;\n"
    "       XPos = 159868.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 202678.718;\n"
    "   }\n"
    "\n"
    "}\n")

As you can see the file consist of numerous objects ("blocks") that can be grouped. This is a nested structure as groups may also be grouped (not shown here). How can I isolate one particular group based on it's name?

So let's say I only want to use "Group 2" in my output file, I would want to get as a result:

Group
{
   Name = "Group 2";
   Index = 5;
   Desc = "Description";
   Block
   {
       Name = "Block 3";
       Index = 112;
       XPos = 122268.472;
       YPos = 0.000;
       ZPos = 208878.718;
   }

   Block
   {
       Name = "Block 4";
       Index = 214;
       XPos = 159868.472;
       YPos = 0.000;
       ZPos = 202678.718;
   }

}

And a similar question for a given block inside a group.

2 Answers2

0

I am quite new to python as well, but I will try to propose a solution for you. I have copied your test_str = ... to an input.txt file and loaded it with python and then used read() method to recreate the string. What you are looking for I believe is the find() method which returns the exact place of a sub-string you are looking for (in this case - groups and blocks). After finding the desired group or block you can then use string slicing as I have used in line blockData = allData[iWantThisBlock:nextBlock] to store only part of a string into a new variable. The code below will print out block 1 from your string. You can use the same methods to get groups, other blocks or parameters from your strings. I really hope this helps you at least a bit :)

import os

os.chdir('D:\\')
fileDir = 'D:\\input.txt'
inputFile = open(fileDir, 'r')

allData = inputFile.read()

iWantThisBlock = allData.find('Block 1')
nextBlock = allData.find('Block 2')

blockData = allData[iWantThisBlock:nextBlock]

print(blockData)
  • With find() method you can also search for curved brackets as well :) – Aivaras Kazakevičius Jan 20 '19 at 14:23
  • Yes, this is what I'm looking for. But the blocks or groups can have any arbitrary name, so I don't know the name of a subsequent group. In this example 'Block 2' could also be 'Bridge 23' or something. – Bob Vanderstok Jan 20 '19 at 16:06
  • I suggest searching for 'name' string in the next block then. You can play around with the find() method and specify a slice of the original string to look for { i.e. allData.find('name', 100, 200) }. For example you can find all indexes were 'name' substring starts in the allData string and then do the slicing according to these indexes. P.S. This way you can also search for curly brackets '{' and '}' as well. – Aivaras Kazakevičius Jan 21 '19 at 07:46
0

I have found the following to work as it will return the proper group based on it's name. Not very generic, but works for now :). It basically counts the number of sets of "{}" until it finds the one belonging to the first (from: https://stackoverflow.com/a/2780461/10940433):

def findGroup( mission, name ):
    start_group = mission.find("   Name = \""+name)
    mission ="Group\n{\n"+mission[start_group:len(mission)]
    if '{' in mission:
      match = mission.split('{',1)[1]
      open = 1
      for index in range(len(match)):
         if match[index] in '{}':
            open = (open + 1) if match[index] == '{' else (open - 1)
         if not open:
            return "Group\n{"+match[:index]+"}\n"

test_str = ("Group\n"
    "{\n"
    "   Name = \"Group 1\";\n"
    "   Index = 2;\n"
    "   Desc = \"Description\";\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 1\";\n"
    "       Index = 497;\n"
    "       XPos = 171568.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 204878.718;\n"
    "   }\n"
    "\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 2\";\n"
    "       Index = 321;\n"
    "       XPos = 162268.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 203478.718;\n"
    "   }\n"
    "\n"
    "}\n"
    "\n"
    "Group\n"
    "{\n"
    "   Name = \"Group 2\";\n"
    "   Index = 5;\n"
    "   Desc = \"Description\";\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 3\";\n"
    "       Index = 112;\n"
    "       XPos = 122268.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 208878.718;\n"
    "   }\n"
    "\n"
    "   Block\n"
    "   {\n"
    "       Name = \"Block 4\";\n"
    "       Index = 214;\n"
    "       XPos = 159868.472;\n"
    "       YPos = 0.000;\n"
    "       ZPos = 202678.718;\n"
    "   }\n"
    "\n"
    "}\n")


print (findGroup(test_str,"Group 2"))