StaticBug
StaticBug

Reputation: 577

Parsing a structured file using Tcl and picking some values?

I have got a semi structured text file, from which I want to extract values and save them for later use. The file has some config data for a simulation environment, the env. is made up of different sub-systems, for one of these sub-systems I want to find the number of them, and their specific type. This is how the file is structured

<Begin_Subsystem_Configuration>
Subsystem_Name:"PLC1_ARR":
Subsystem_Identifier:0x01B1B000:
Subsystem_Type:PLC_BERGHOF:
IP_Address:"10.70.9.11":
Port_Numbers:3500:3500:
Alive_Message_Period:10:
Max_Communication_Latency:5:
Switch_Over_Timeout:15:
Member_Count:6:
Subsystem_Member_1:77:77:       # PS SR1
Subsystem_Member_2:106:106:     # SZ PTHA
Subsystem_Member_3:110:110:     # SZ PTH1
Subsystem_Member_4:310:310:     # SZ YL1
Subsystem_Member_5:311:311:     # SZ DOOR1
Subsystem_Member_6:312:312:     # SZ FIRE1
<End_Subsystem_Configuration>

Now I want to know, how often the pattern PLC_BERGHOF Occur in the file, I actually can do that already, but now if it is found I would like to save in some sort of assoc. array the key-value pair of the line before, and the 3 lines after the line in which the patter found.

Later on in my script I would like to be able to access the values like that: set plc1_IP_Address array['plc1_IP_Address'], the exact sysntax of accessing that doesnt really matter, the code has just to go into a Tcl Script

Thanks for the help

Upvotes: 1

Views: 1009

Answers (2)

glenn jackman
glenn jackman

Reputation: 246754

set fh [open "file.data" r]
array set data []
while {[gets $fh line] != -1} {
    switch -exact -- $line {
        "<Begin_Subsystem_Configuration>" -
        "<End_Subsystem_Configuration>"   {continue}
        default {
            set fields [split $line ":"]
            set values [list]
            foreach value [lrange $fields 1 end-1] {
                if {[string match {"*"} $value]} {
                    lappend values [string range $value 1 end-1]
                } else {
                    lappend values $value 
                }
            }
            set data([lindex $fields 0]) $values
        }
    }
}
close $fh

Then you can use

if {$data(Subsystem_Type eq "PLC_BERGHOF"} {
    puts "IP address is: $data(IP_Address)"
}

I assume your file is actually formatted as following, and you were having trouble getting your question formatted just right:

<Begin_Subsystem_Configuration>
Subsystem_Name:"PLC1_ARR":
...
<End_Subsystem_Configuration>

Upvotes: 0

patthoyts
patthoyts

Reputation: 33193

If you are using Tcl 8.5 then I suggest you read the file line by line building up a set of dict objects to hold each subsystem as a collection of name:item pairs. You can then create a list of such dicts to represent the whole file or whatever makes sense to you. Then something like:

foreach config $list_of_dicts {
    if {[dict get $config Subsystem_Type] eq "PLC_BERGHOF"} {
        puts "[dict get $config IP_Address]\n[dict get $config Port_Numbers]"
    }
}

Although from the sound of your description: grep -A 3 PLC_BERGHOF would be sufficient.

If not using 8.5 then you don't have dict but a list of name item pairs can be managed in much the same way. You just end up using lsearch more or converting the list of pairs into an array just to look things up.

Upvotes: 3

Related Questions