Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: TCL code to read a following file

8 views
Skip to first unread message
Message has been deleted

Alexandre Ferrieux

unread,
May 19, 2007, 2:55:05 PM5/19/07
to
On May 19, 3:36 pm, nehal <sowmya.ne...@gmail.com> wrote:
> How to read the following file using arrays in a tcl code.
> (nested constructs)

Hint :use regsub to replace all your "begin foobar"s by "foobar {",
and all your "end"s by "}".
Then use [eval].

-Alex

Cameron Laird

unread,
May 19, 2007, 5:09:56 PM5/19/07
to
In article <1179600905....@u30g2000hsc.googlegroups.com>,
.
.
.
Alex, while regsub will of course do fine for these substitutions,
how did you decide against [string map]?

Alexandre Ferrieux

unread,
May 19, 2007, 6:20:33 PM5/19/07
to
On May 19, 11:09 pm, cla...@lairds.us (Cameron Laird) wrote:
> In article <1179600905.738853.34...@u30g2000hsc.googlegroups.com>,

> Alexandre Ferrieux <alexandre.ferri...@gmail.com> wrote:>On May 19, 3:36 pm, nehal <sowmya.ne...@gmail.com> wrote:
> >> How to read the following file using arrays in a tcl code.
> >> (nested constructs)
>
> >Hint :use regsub to replace all your "begin foobar"s by "foobar {",
> >and all your "end"s by "}".
> >Then use [eval].
>
> .
> .
> .
> Alex, while regsub will of course do fine for these substitutions,
> how did you decide against [string map]?

It's just that I'm not used to it; I like the genericity and power of
the re engine.
Moreover, I understand there are optimizations under the hood for the
most common cases.
So quite possibly the [regsub] variant would run just as fast as the
[string map]...
(no flames please, I didn't check).

In addition, the added power of regexps can be put to good use by the
OP in more complicated situations (like when the number of spaces
between words is not guaranteed constant).

So, as you can see, no single good reason, just a vector of them ;-)

-Alex

Cameron Laird

unread,
May 19, 2007, 8:09:42 PM5/19/07
to
In article <1179613233.7...@n59g2000hsh.googlegroups.com>,
.
.
.
I can well understand that.

I'm glad I raised the question, because it's appropriate to
mention that Tcl's REs are particularly trustworthy <URL:
http://www.unixreview.com/documents/s=10121/ur0702e/ >; while
I hadn't thought of it when I first wrote, this is a nice
example of how focus on the more general style--RE, in this
case--is good programming, because the implementation itself
can take care of salient optimizations. Good point.

On the other hand, REs intimidate some newcomers, who find
[string map] (for example) friendlier. I don't know if that's
the case for sowmya.

My immediate motivation, though, was that you counseled *two*
substitutions; for my use of Tcl, [string map] is the more
idiomatic approach when substitutions are multiple.

Alexandre Ferrieux

unread,
May 20, 2007, 3:29:44 PM5/20/07
to
On May 20, 2:09 am, cla...@lairds.us (Cameron Laird) wrote:
> My immediate motivation, though, was that you counseled *two*
> substitutions; for my use of Tcl, [string map] is the more
> idiomatic approach when substitutions are multiple.- Hide quoted text -

Oh, you're quite right. Running several [regsub]'s in sequence tends
to be largely slower than the equivalent [string map] (though you can
offset that effect with the "|" operator inside regexps).
However, there's an alternative: approximate by a superlanguage, IOW
be overgenerative.
Loosely speaking, the larger the language, the smaller the automaton.

For the example at hand, the pair of calls

regsub -all {Begin([A-Z][A-Za-z0-9]+)} $s "my_\\1\{" s
regsub -all {End[A-Z][A-Za-z0-9]+} $s "\}" s

handles any number of Begin/End varieties in just two scans...
Of course doing this delays some checking (the superlanguage *is* an
approximation), but it's trivial to do the checks afterwards (e.g.
with [unknown] to catch unexpected BeginXYZ, mapped to my_XYZ above).

-Alex

sleb...@gmail.com

unread,
May 20, 2007, 11:59:40 PM5/20/07
to
On May 21, 3:29 am, Alexandre Ferrieux <alexandre.ferri...@gmail.com>
wrote:

It should be noted at this point that [string map] will generate a
slightly different looking list. So the choice also in part depends on
how easy it is to process the resulting list:

regsub -all {Begin([A-Z][A-Za-z0-9]+)} $s "\\1 \{" s


regsub -all {End[A-Z][A-Za-z0-9]+} $s "\}" s

result:

Case:1 {
List:1 {
Stress
}
List:3 {
Stress|(Min)|VonMises
}
List:8 {
Stress
}
List:9 {
Stress
}
List:12 {
Stress
}
}

set s [string map [list Begin "{" End* "}"] $s]

result:

{Case:1
{List:1
Stress
}
{List:3
Stress|(Min)|VonMises
}
{List:8
Stress
}
{List:9
Stress
}
{List:12
Stress
}
}

The regsub solution generates a clean looking two-level nested dict.
The string map solution on the other hand, due to not being able to
extract \1, is slightly messier but managable if we use:

http://wiki.tcl.tk/16032

nehal

unread,
May 21, 2007, 12:59:25 AM5/21/07
to
On May 19, 6:36 pm, nehal <sowmya.ne...@gmail.com> wrote:
> How to read the following file using arrays in a tcl code.
>
> I should store all the begincase ids in one variable and beginlist ids
> in one variable and contents between the BeginList and EndList in one
> variable and I should pass all these arguments to a another file.
> BeginList is dependent on BeginCase..
> Each beginCase contain so many beginLists.
>
> BeginCase:1
> BeginList:1
> Stress
> EndList
> BeginList:3
> Stress|(Min)|VonMises
> EndList
> BeginList:8
> Stress // Elements, ByID, 12, 14, 67
>
> EndList
> BeginList:9
> Stress
> EndList
> BeginList:12
> Stress
> EndList
> EndCase
> BeginCase:2
> BeginList:(All)
> Displacement // Nodes, ByID, 1,45,67,104-106
>
> Strain Energy|Strain Energy
> Strain Energy|Energy Density
> EndList
> EndCase
> BeginCase:3
> BeginList:1
> Displacement
> EndList
> EndCase


Here first i should list all the Begincase Ids, then all the BeginList
ids for the each Begincase, then the contents between each beginlist
and endlist in one variable. so then i need to pass all these to
another procedure...
say...
case list type entity
method ids
1 1 stress -
- -
3 Stress|(Min)|VonMises -
- -
8 stress element ByID
12,14, 67
9 stress -
- -
12 stress -
- -
2 all displacement nodes ByID
1,45,67,104-106
Strain Energy|Strain Energy -
- -
train Energy|Energy Density -
- -
3 1 Displacement -
- -

Please anyone help me in this regards... can i first store all case,
list, type, entity,method and ids in a different list (each list for
each variable to store its contents) and then all in the array!!! Its
ver urgent.. If anyone could me help out in this!!!

mark anthony

unread,
May 21, 2007, 11:23:34 AM5/21/07
to
##On May 21, 6:59 am, nehal <sowmya.ne...@gmail.com> wrote:
##> Please anyone help me in this regards... can i first store all
case,
##> list, type, entity,method and ids in a different list (each list
for
##> each variable to store its contents) and then all in the array!!!
Its
##> ver urgent.. If anyone could me help out in this!!!
##
##
## somehow this looks like homework to me... i hope it's not.
##
## if it is homework, dont use the code below. do it yourself.
##
## but it uses one big list instead of 3 variables.
##
## anyhow here are two unsophisticated version that are not fancy:
##


set data {BeginCase:1

## read the file
proc retrieve { file } {

set filename ""
set ch [open $filename]
set data [read $ch]
close $ch
return $file
}

## returns a list like:
##
## {
## caseid0
## {
## listid0
## { contentline0 contentline1 ... }
## listid1
## { contentline0 }
## }
## ...
## }
##
proc parse { data } {

## the thing
set result [list ]

## temp
set sublist [list ]
set contentlist [list ]

set case 0 ; ## 0 begincase, 1 begincase, 2 content

foreach line [split $data "\n"] {
set line [string trimleft $line]

if {"EndCase"eq$line} then {
lappend result $sublist
set sublist [list ]
incr case -1
continue
}
if {"EndList"eq$line} then {
lappend sublist $contentlist
set contentlist [list ]
incr case -1
continue
}

## data handling
::switch $case {
0 {
## i should be a BeginCase

## assertion
set splited [split $line ":" ]
if {"BeginCase"ne[lindex $splited 0]} then {
## silently ignore lines,
## until we find something useful
continue
}

## in case we have an id with collon
set caseId [join [lrange $splited 1 end ] ":" ]

## adding the data
lappend result $caseId

incr case
}
1 {
## i should be a BeginList

## assertion
set splited [split $line ":" ]
if {"BeginList"ne[lindex $splited 0]} then {
## die hard
return -code error "EXPECTED_BEGINLIST"
}

## in case we have an id with collon
set listId [join [lrange $splited 1 end ] ":" ]


lappend sublist $listId
::incr case
}
2 {
## ignore empty lines
::if {""eq$line} then {
continue
}
## i'm a Contentline
lappend contentlist $line
}
default {
::return -code error "NO_SUCH_CASE"
}
}
}
return $result
}
##
## testing if parse works and to show how to access
## the parsed data
##
proc test { data } {
## here goes your handling
foreach [list id sub ] [parse $data] {
foreach [list lid contents ] $sub {
::foreach line $contents {
::puts "$id :: $lid :: $line"
}
}
}
}


##
## Or you could spawn your calls in case 2 directly e.g.
## like this.
##
## just pass write a callback that better fits your need
##
proc out { case list type } {
puts "$case :: $list :: $type "
}

proc pass { data { callback out } } {
set case 0 ; ## 0 begincase, 1 begincase, 2 content
foreach line [split $data "\n"] {
set line [string trimleft $line]

if {"EndCase"eq$line} then {
incr case -1
continue
}
if {"EndList"eq$line} then {
incr case -1
continue
}

## data handling
::switch $case {
0 {
## i should be a BeginCase

## assertion
set splited [split $line ":" ]
if {"BeginCase"ne[lindex $splited 0]} then {
## silently ignore lines,
## until we find something useful
continue
}

## in case we have an id with collon
set caseId [join [lrange $splited 1 end ] ":" ]

incr case
}
1 {
## i should be a BeginList

## assertion
set splited [split $line ":" ]
if {"BeginList"ne[lindex $splited 0]} then {
## die hard
return -code error "EXPECTED_BEGINLIST"
}

## in case we have an id with collon
set listId [join [lrange $splited 1 end ] ":" ]
incr case
}
2 {
## ignore empty lines
if {""eq$line} then {
continue
}
## i'm a Contentline

## here goes your calling
$callback $caseId $listId $line
}
default {
::return -code error "NO_SUCH_CASE"
}
}
}
return
}

Alexandre Ferrieux

unread,
May 21, 2007, 12:21:20 PM5/21/07
to
On May 21, 6:59 am, nehal <sowmya.ne...@gmail.com> wrote:

> Please anyone help me in this regards... can i first store all case,
> list, type, entity,method and ids in a different list (each list for
> each variable to store its contents) and then all in the array!!! Its
> ver urgent.. If anyone could me help out in this!!!

You didn't like the other replies, did you ?
Okay, let's do it for you.. this time :-)

regsub -all {Begin([A-Z][a-z]*):([0-9A-Za-z()]+)} $data "my_\\1 \
\2 \{" data
regsub -all {End[A-Z][a-z]*} $data "\}" data
set ids {}
proc my_Case {id code} {lappend ::ids $id;set ::thecase $id;eval
$code}
proc my_List {id code} {lappend ::lists($::thecase)
$id;set ::codes($::thecase,$id) $code}
eval $data

Simple, eh ?
To convince yourself that it works:

puts "ids=$ids"
parray lists
parray codes

-Alex

nehal

unread,
May 22, 2007, 7:04:05 AM5/22/07
to


I tried working like this, Its giving an error for incr case -1, could
U please check and let me know.. which is the way to do this.. Its
very urgent.

Larry W. Virden

unread,
May 22, 2007, 8:21:03 AM5/22/07
to
On May 22, 7:04 am, nehal <sowmya.ne...@gmail.com> wrote:

> I tried working like this, Its giving an error for incr case -1, could
> U please check and let me know.. which is the way to do this.. Its
> very urgent.

Two suggestions:

1. provide us the output from the following:
a. parray tcl_platform
b. info patchlevel

2. provide us the exact error msg you are getting .

0 new messages