On Thu, 2 Mar 2006, Andreas Leitgeb wrote:
> So what one really needs in this situation is a procedure or command
> that does the following for a given string:
> 1.) try to treat it as list: if it works out,
> return [lrange $str 0 end].
> 2.) if any non-blank prefix of the string is acceptable as
> a list, find a maximal such prefix, convert that to a
> list, and apply "3.)" on the rest.
> 3.) apply something like [split] on the rest, or treat the
> rest as one item.
>
> The second of that is non-trivial on tcl-level, especially when taking
> performance into account.
Trivial it is, performing well is out of the question :)
> I'm not proposing any new core-features (at least not on this topic),
> but if someone wrote a "reasonable list parser", it might be a valueable
> gem on wiki or tcllib.
This is just something I cooked together while waiting for Married.. with
Children to begin. Now it begins, so I'll post this now. Bye.
<some code below>
package require Tcl 8.5; # lassign
# REAsonable LiSt PArser
# not REAsonable List pARSEr
proc realspa {victim} {
# so, if it is a list, then we'll return it
if {![catch {llength $victim}]} {return [lrange $victim 0 end]}
# so, it isn't a list. fine by me
# there shall be no empty units in either end
set victim [string trim $victim]
# then we need something to cut this at
set cil [regexp -all -indices -inline {\s+} $victim]
# there are basically two ways to find out where a string is no more a list
# 1) add stuff from the beginning until it breaks
# 2) take stuff from the end until it doesn't break
# 1 is the easy way out, but it'll break in my example too early
# so case 2 it'll be
# indices need to be reversed (courtesy of KPV)
set st -1
set en [llength $cil]
foreach tm $cil {
if {[incr st] >= [incr en -1]} {break}
lset cil $st [lindex $cil $en]
lset cil $en $tm
# http://wiki.tcl.tk/43 has following line too much
# incr st
}
# puts "cil=$cil"
foreach sep $cil {
lassign $sep s e
# puts "s=$s, e=$e, r=[string range $victim 0 $s-1]"
if {![catch {llength [string range $victim 0 $s-1]}]} {break}
}
# at this point we should know where it broke, and the rest is final cell
set lst [lrange [string range $victim 0 $s-1] 0 end]
lappend lst [string range $victim $e+1 end]
}
set t "this is one {malfor matted} {list"
puts "trying out >>$t\ninvalid list? [expr {[catch {llength $t}]?yes:no}]"
set l [realspa $t]
puts "recovered (or used) [llength $l] cells"
foreach i $l {puts "->$i<<<"}
<no more code here>
--
-Kaitzschu
s="TCL ";while true;do echo -en "\r$s";s=${s:1:${#s}}${s:0:1};sleep .1;done
Received on Sun Apr 30 02:20:45 2006