Answered Questions On: Advanced Tcl


NAVIGATION


TABLE OF CONTENTS (Advanced Tcl):

  • Lists - The Lrange Command - Complex Data Structures Using Lists
  • How Do I Pass A Variable/Value To A Child Interpreter?
  • Tcl String Command Syntax/Usage: Concat - Subst - Args

SEE ALSO:

  • ...

Lists - The Lrange Command - Complex Data Structures Using Lists

2003/01/20

Is there a real way to do the following?

 proc lranges {list args} {

     set start 0
     set newlist {}
     foreach size $args {
         set end [expr {$start + $size - 1}]
         lappend newlist [lrange $list $start $end]
         incr start $size
     }
     if {$start <= [llength $list]} {
         lappend newlist [lrange $list $start end]
     }
     return $newlist
 }

 % lranges "1 2 3 4 5 6 7" 2 3 5
 {1 2} {3 4 5} {6 7} 

I was getting tired of parsing things with continual lranges and I kept wishing I could foreach over a however many elements I wanted to grab for the next variable instead of just one.

Not sure this has a good default behavior, and I should probably error handle non integer args.

BR 2004-01-21 - Can you give an real example of what you want to do? Are you looking for something like:

  foreach {label value} {firstname "Benny" lastname "Riefenstahl"} {
      # Do something with $label and $value
  }

sheila 2004-01-21 - I'd like to be able to do this:

  foreach {opcode control data1 data2} {01 02 89 24 35 87 52 45 38 48} {break}

opcode will be 01, control 02, data1 {89 24 35 87 52}, and data2 {45 38 48}

assuming that I know the byte count of each field. iow:

  set message {01 02 89 24 35 87 52 45 38 48}
  foreach {opcode control data1 data2} [lranges $message 1 1 5] {break}

instead of

  set opcode [lrange $message 0 0]
  set control [lrange $message 1 1]
  set data1 [lrange $message 2 6]
  set data2 [lrange $message 7 end]

There are more complicated uses (like with a byte count field, and then foreaching based on that), but is this example sufficient?

BR 2004-01-22 - To answer the original question, no I don't think there is a built-in solution for this. But if you are ok with the concept, your proc is o.k., isn't it? I personally would probably prefer to write it out as you do above, unless I have lots of repeating code in a specific module.

Notes:

  • In the abstract there are no "byte counts" in this, unless the numbers are byte values in your specific example. If you are starting out with binary data, you may want to consider more involved uses of binary scan.
  • The first two items in your example results are logically lists. This will make a difference with more complicated list items. In theory Tcl is even allowed to represent these lists differently in this very example today, e.g. as {01} {02}. Although it is unlikely Tcl will ever change here, as this would expose bugs in too many applications. ;-)

sheila 2004/01/22 - Thanks. I wanted to make sure I wasn't overlooking some tcl function. The reason I want the proc is that I don't like all of the hard coded numbers making my parsers unreadable. I make data structures for the commands, and then I have retrieval proc to return whatever value of the command I specify in the structure, i.e. byte length, length of a field, etc. That way I can have self-documenting code. Also, when I do pass in a value in a message that represents a byte length, and the message I'm parsing is variable length based on another value that is the number of foobar in the message. Then using the lranges command makes it a lot easier to read rather than many lrange calls for however many fields are in the fields that I'm parsing. (once I asked in the newsgroup whether there was a package anyone had written to already do this, but there wasn't.)

I suppose I make the trade off in efficiencey for readability, but I don't think it will slow down the parsing enough to be a problem.

Is there a better way to do this? (am I making this question too long for this page? apologies. I could move it somewhere else.)


Tcl String Command Syntax/Usage: Concat - Subst - Args

14/Aug/2003

I am trying to define a data structure recursively and can't get it to work.

Any suggestions?

The idea is from: http://users.pandora.be/koen.vandamme1/papers/tcl_fileformats/tcl_fileformats.html

I would expect "A=atts" I would expect "B={atta bttb} {cttc dttd}" Then I would expect "A=pins" I would expect "B={pin4 four} {pin5 five}"

I do not get that. I have also tried numerous other things like concat, subst, etc... to no avail.

   proc mycommand { args } {

    foreach { a b } [concat $args] {
        puts "A=$a"
        puts "B=$b"
    }
   }

   mycommand {
    atts {
        { atta bttb }
        { cttc dttd }
    }

    pins {
        { pin4 four }
        { pin5 five }
    }
   }

tje Aug 20 2003 - Try this:

    proc mycommand {in} {foreach {a b} $in { puts "A=$a" ; puts "b=$b" } }

Remember that args is a special argument that wraps multiple arguments into one.