0
votes
Loop = ( 
      {
        Value = ( 
          {
           {
            Key : 
            {
              A = "B";
              C = "D";
              Class = ( 
                {
                  section = "section_a";
                  Pairs = ( 
                    {
                      Name = "Ram";
                      Mark = "80";
                    }, 
                    {
                      Name = "Latha";
                      Mark = "70";
                    }, 
                    {
                      Name = "Mohan";
                      Mark = "90";
                    }, 
                    {
                      Name = "David";
                      Mark = "76";
                    } );
                } );
              Id = 1;
            };
            Absent : 
            {
              DAYS = "Two days";
            };
          }, 
           {
            Key : 
            {
              A = "B";
              C = "D";
              Class = ( 
                {
                  section = "section_b";
                  Pairs = ( 
                    {
                      Name = "Ram";
                      Mark = "30";
                    }, 
                    {
                      Name = "Latha";
                      Mark = "45";
                    }, 
                    {
                      Name = "Mohan";
                      Mark = "100";
                    }, 
                    {
                      Name = "David";
                      Mark = "76";
                    } );
                } );
              Id = 2;
            };
            Absent : 
            {
              DAYS = "Four days";
            };
          }, 
          } );
      } );

I am new to tcl script. I have a txt file in a above format. Using tcl script I have to store strings(section, Name , mark and Absent days) in a different variables to store in a csv file. I tried below code to search the word Key

set search "Key"
set file [open "Marks.txt" r]
 while {[gets $file data] != -1} {
    if {[string match *[string toupper $search]* [string toupper $data]] } {
        puts "Found '$search' in the line '$data'"
    } else {
        puts "does not match" 
    }
 } 

It is working to find the word key and printing whenever it matches. It works for that line which has the word Key. But, here I want to find the word Loop then I want search for the word Key in side loop. If it sees the word Key then it has to copy some strings present in the loop to variables. The word Key will be repeated in the files multiple times. After the word Key there will be {..} all over there file has some content. The script has to read the content and store it in some variable.

Exp: The script need to find the word Key in the text file, then look for the section if present then section_b need to be stored in variable temp1(exp. temp1=section_a), Like wise:
If it sees Ram then Mark below the line needs to be stored in temp2 (exp. temp2=80).
If it sees Latha then Mark below the line needs to be stored in temp3 (exp. temp3=70).
then find id and need to to store the value 1 need to be stored in temp4(exp. temp4=1).
then Days meed to be stored in temp5(exp. temp5=Two days)

These temp values need to be written in the csv file everytime when it sees the word Key in the text file in below format.

section     Ram  Latha   id    Days
Section_a    80   70     1    Two days
Section_b    30   45     2    Four days

Can you help me in writing the tcl script to get this. Thank you.

1
That's a moderately complicated format you're trying to parse there…Donal Fellows
It's more initial work, but if you're doing a lot with this file format, using the parser generators in tcllib to make a package to read the format might be worthwhile.Shawn

1 Answers

0
votes

This is the kind of thing that awk is really good for:

awk '
    function quoted(string,     a) {
        split(string, a, /"/)
        return a[2]
    }
    BEGIN { OFS="\t"; print "section", "Ram", "Latha", "id", "Days" }
    $1 == "section" {section = quoted($0); delete marks}
    $1 == "Name" {name = quoted($0)}
    $1 == "Mark" {marks[name] = quoted($0)}
    $1 == "Id" {id = gensub(/;/, "", 1, $3)}
    $1 == "DAYS" {print section, marks["Ram"], marks["Latha"], id, quoted($0)}
' file

Translating that as a Tcl "one-liner", I'd write

echo '
    proc trim {str} {string trim $str {"}}
    puts "section\tRam\tLatha\tid\tdays"
    set fh [open [lindex $argv end]]
    while {[gets $fh line] != -1} {
        if {[regexp -- {(\S+) = ("[^"]+"|\d+);} $line -> key value]} {
            switch -exact -- $key {
                section {set section [trim $value]; array set marks {}}
                Name    {set name [trim $value]}
                Mark    {set marks($name) [trim $value]}
                Id      {set id $value}
                DAYS    {puts [join [list $section $marks(Ram) $marks(Latha) $id [trim $value]] \t]}
            }
        }
    }
' | tclsh - file