Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations IamaSherpa on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

How can I add spaces into a list? 3

Status
Not open for further replies.

FreddieBlassie

Programmer
Dec 11, 2001
20
US
I have a list variable, RSTPattern, with value:

{00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01000000 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }

I'd like to know how I can add spaces between the values that currently do not have spaces, as this is required. I am trying to find a way to do it using linsert, but am having no luck. The first space should be set in the 18th index of the list. Something like: set RSTPattern $[linsert $RSTPattern 18 " "]
Of course that doesn't work, but am I on the right track? Not sure my syntax is correct there. If something like this won't work to accomplish it, what will?
 
Actually it should be set between the 19th and 20th index, so I'm not sure exactly how to do it.
 
Actually the 18th index equals 01, 19th equals 00 so i had it right the 1st time. It should be between 18 and 19.
 
well it should be treating 01000000 as a single list element, element 18, so I guess what I need to figure out is how to divide this up into separate elements in groups of 2.
 
I suppose if I could find a way to do it just by using the value as a string, that would work just as well since the value is a string before I insert it into the RSTPattern list. I am looking into using the string trim commands to do this. So if this would work, I could just set the list like



set HexNum2 $HexNum
set HexNum3 $HexNum
set HexNum4 $HexNum

string trimright $HexNum 6
etc.
string trimleft $HexNum4 6




set RSTPattern "{00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 $HexNum $HexNum2 $HexNum3 $HexNum4 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }"


as opposed to setting it as simply:

set RSTPattern "{00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 $HexNum 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }"


So far I haven't got this method to work either though.
 
Maybe avia can help with the problem of converting a list
to a string and vice versa.

Either way this little snippet works to separate
the blocks into two char lengths.

set yours {00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01000000 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }

proc garble {str} {
upvar $str loc_str
set new ""
set ii [split $loc_str ""]
for {set i 0} {$i <= [string length $loc_str]} {incr i 2} {
set n [string range $ii [expr $i - 1] $i]
scan $n &quot;%s&quot; n
append new $n
}
return $new
}

set revstr [garble yours]

The problem is that the returned value is still list formatted. I'm too tired to break that one right now.

Good Luck.
 
I'm not sure I see what you're after. Something like this:?

set lst1 {00 27 42 42 03 00 00 02}
00 27 42 42 03 00 00 02
lappend lst1 01000000
00 27 42 42 03 00 00 02 01000000
lappend lst1 01
00 27 42 42 03 00 00 02 01000000 01
#for example. Now you have a list
set newvar [lindex $lst1 8]
01000000
for {set i 0} {$i<=3} {incr i} {
set ix1 [expr $i*2]
set ix2 [expr $ix1+1]
set var$i [string range $newvar $ix1 $ix2]
}
set lst2 [lreplace $lst1 8 8 $var0 $var1 $var2 $var3]
00 27 42 42 03 00 00 02 01 00 00 00 01 Bob Rashkin
rrashkin@csc.com
 
The output i got when i used that code marsd was
\{00{}27{}42{}42{}03{}00{}00{}02{}02{}0C{}00{}00{}00{}22{}22{


What I'm looking to do is to change this: {00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01000000 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }

to this: {00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01 00 00 00 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }


Or to take the string value of HexNum, 01000000, and convert that into a list {01 00 00 00}, to be inserted into the other list.
 
Wow. Took me a while to wade through all those self-responses. I think I've figured out where you are now, but let me take this step by step, just to make sure you're following everything.

First of all, as you've seemed to have figured out, the value &quot;01000000&quot; is being treated as a single list element. That is because in Tcl, a list is a whitespace-separated sequence of elements. The whitespace can be any number of spaces, tabs, or embedded newline characters. An element can be any string value. However, if the value of an element contains whitespace characters or other significant Tcl characters, the list element must be quoted, following the standard Tcl quoting rules. If you use Tcl's list commands (such as list, lappend, lindex, etc.) to build and manipulate your lists, they automatically take care of any quoting issues needed to keep elements intact and valid.

Because you're building this list yourself, rather than reading in a &quot;pre-built&quot; list from a file or elsewhere, it's going to be easiest by far to split up a long value like &quot;01000000&quot; into separate pieces before inserting it into the list. But the string trim commands aren't going to do that for you. The string trim commands &quot;chop off&quot; any occurrences of the characters you specify from the beginning and/or the end of the input string. For example, to trim all leading 0s from a string:

[tt]% string trimleft 000342 0
342[/tt]

But, in the following:

[tt]% string trimright &quot;42.0;&quot; &quot;.;&quot;
42.0[/tt]

in trying to chop off all occurrences of &quot;.&quot; and &quot;;&quot; characters from the end of the string, string trimright chopped the &quot;;&quot;, but then encountered a character other than one of the &quot;chop&quot; characters, and so stopped. It doesn't &quot;dig in&quot; to the string past the point where it encounters a &quot;non-chop&quot; character.

Anyway, back to the idea of splitting a string. The command you want is string range, which returns a substring given the beginning and ending indices you specify. (Just remember that Tcl starts counting characters at 0!). Here are some examples:

[tt]% string range &quot;Avia Training&quot; 1 9
via Train
% string range &quot;Avia Training&quot; 0 3
Avia
% string range &quot;Avia Training&quot; 5 end
Training
% string range &quot;Avia Training&quot; end-7 end-3
Train[/tt]

So, we could combine this with a for loop to split of the long string. Without knowing exactly how you're building up the rest of your list, it's difficult to say what's the best approach. But let's examine an example of what I've got in mind.

First of all, I noticed a problem in the code fragment you gave for building your list. You said:

Code:
set RSTPattern   &quot;{00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 $HexNum 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }&quot;

If this is what you're really doing, you're in for trouble treating this thing as a list because you've quoted your argument twice. The value you've assigned to RSTPattern is:

{00 27 ... 00 00 }

with the {}s included as part of the value. To Tcl, this looks like a single, quoted list element. In other words, you've built a one-element list rather than a multi-element list. So, we're going to have to eliminate one set of quotes or the other for you to have a proper multi-element list.

In my example code, I'm also going to use a couple of other list commands to help build up the list: lappend, which adds one or more elements to an existing list stored in a variable; and concat which merges two or more lists together as its return value. Check the reference pages for more information on these commands.

Code:
# Set the initial elements of our list
set RSTPattern {00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22}

# Break up our big string into separate
# elements, and append them to the initial
# segment of the list.

set val &quot;01000000&quot;
set len [string length $val]

for {set i 0} {$i < $len} {incr i 2} {
  set end [expr {$i + 1}]
  lappend RSTPattern [string range $val $i $end]
}

# Concatenate the remaining elements to
# the end of the list.

set RSTPattern [concat $RSTPattern {00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }]

As an advanced aside, for those of you interested in regular expressions, as of Tcl version 8.3, we can take advantage of a couple of new regexp options. The -inline option causes regexp to return the matched pattern, rather than storing them directly in a variable. (If your pattern includes subpatterns, the return value is a list consisting of the entire match as the first element, and then each subpattern match as subsequent elements.) The -all option returns all matches rather than just the first. This is very useful in combination with -inline. To illustrate its relevance to this problem, the following command takes a string and chops it into a list of 2-character elements (if the number of characters is odd, the last element will consist of just a single character):

[tt]% regexp -inline -all {..?} abcd
ab cd
% regexp -inline -all {..?} abcdefg
ab cd ef g[/tt]

So, in the code fragment above, we could replace the entire for loop with:

Code:
set RSTPattern [concat $RSTPattern [regexp -inline -all {..?} $val]]
- Ken Jones, President
Avia Training and Consulting
866-TCL-HELP (866-825-4357) US Toll free
415-643-8692 Voice
415-643-8697 Fax
 
If your list is a regular list with string items, you can do:

Code:
set l1 {&quot;00&quot; &quot;27&quot; &quot;42&quot; &quot;42&quot; &quot;03&quot; &quot;00&quot; &quot;00&quot; &quot;02&quot; &quot;02&quot; &quot;0C&quot; &quot;00&quot; &quot;00&quot; &quot;00&quot; &quot;22&quot; &quot;22&quot; 
        &quot;22&quot; &quot;22&quot; &quot;22&quot; &quot;01000000&quot; &quot;00&quot; &quot;00&quot; &quot;22&quot; &quot;22&quot; &quot;22&quot; &quot;22&quot; &quot;22&quot; &quot;23&quot; &quot;00&quot; &quot;01&quot;
        &quot;00&quot; &quot;00&quot; &quot;00&quot; &quot;00&quot; &quot;0A&quot; &quot;00&quot; &quot;00&quot; &quot;00&quot; }
set l2 {}
foreach i $l1 {
  while {[string length $i] > 2}   { 
    lappend l2 [string range $i 0 1]
    set i [string range $i 2 end]
  }
  lappend l2 $i
}
puts $l2
00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01 00 00 00 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00

ulis
 
ahh...i didn't look at the range command, or see any examples in the book. Well thanks guys, both of your methods seem to work. I finally got it working here. Thanks a lot!
 
Unless you use ulis' way to format your list, the other solutions fail when the data is generated dynamically.

This function will work on any length list formatted as yours was without fail except that it has a little bug.
if you run in to it let me know ;)


set yours {00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01000000 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00 }

proc garble {str} {
upvar $str loc_str
set new &quot;&quot;
set ii [split $loc_str &quot;&quot;]
regsub -all &quot; &quot; $ii &quot;&quot; ii
regsub -all &quot;\{\}&quot; $ii &quot;&quot; ii
for {set i -1} {$i <= [string length $loc_str]} {incr i 2} {
set n [string range $ii [expr $i - 1] $i]
append new &quot;$n &quot;
}
return $new
}

set revstr [garble yours] ; puts $revstr
output:
00 27 42 42 03 00 00 02 02 0C 00 00 00 22 22 22 22 22 01 00 00 00 00 00 22 22 22 22 22 23 00 01 00 00 00 00 0A 00 00 00

IMO having any set variable before the long element is
discovered is faux, and picking out the long single
element and then rejoining the list is not really a good
method. I could be wrong. ;-)
 
Yes I did I have to remove one set of brackets Avia. I had added the outer parenthesis because the variable subsitution wouldn't occur if the list had simply been quoted with the {}, but I removed the inner brackets after you made the point about the double-quotes. Marsd your solution works in my program too now that i've fixed the double-quotes. Thanks for your help guys!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top