Updated 2018-05-14 15:57:07 by SYStems

```# Allow spaces and underscores in long number for easy reading
proc norm {num} {
if {[regexp {^(\s|\d|_)*(\.)?(\s|_)*(\d)+(\s|\d|_)*\$} \$num]} {
string map {_ {} \  {}} \$num
} else {
error "Number: \$num is not in normal form"
}
}

Example:
expr {[norm 10_000_000] + [norm 100._10_100]}
=> 10000100.101```

More on string reversal

AMG: Neat! Here, this proc does the reverse (adds underscores):
```proc abnorm {num} {
if {![string is double -strict \$num]} {
error "not a number: \"\$num\""
}
set point [string first . \$num]
if {\$point == -1} {
set point [string length \$num]
} else {
for {set pos [expr {\$point + 4}]} {\$pos < [string length \$num]} {incr pos 4} {
set num [string replace \$num \$pos \$pos _[string index \$num \$pos]]
}
}
for {set pos [expr {\$point - 3}]} {\$pos > 0} {incr pos -3} {
set num [string replace \$num \$pos \$pos _[string index \$num \$pos]]
}
return \$num
}```

Example:
```% abnorm 100.10100
100.101_00
% abnorm 10000000
10_000_000
% abnorm 10000100.101
10_000_100.101```

This code doesn't handle exponential notation or even negative numbers. I don't want to put much more effort into it, since I'm more interested in seeing some clever [regsub] version. If anyone wants to give it a try, ... go right ahead. Have a blast.

AMG: I woke this morning with an inspiration about how to do this with [regsub].
```proc sreverse {str} {
set result ""
for {set i [expr {[string length \$str] - 1}]} {\$i >= 0} {incr i -1} {
append result [string index \$str \$i]
}
return \$result
}

proc abnorm {num} {
if {![string is double -strict \$num]} {
error "not a number: \"\$num\""
}
regexp {^(-|\+)?(\d+)?(\.)?(\d+)?(e|E)?(-|\+)?(\d+)?\$} \$num num sm int dot frac e se exp
set result \$sm
append result [regsub -all {(?!^)(?=(\d{3})+\$)} \$int _]
append result \$dot
append result [sreverse [regsub -all {(?!^)(?=(\d{3})+\$)} [sreverse \$frac] _]]
append result \$e\$se\$exp
return \$result
}```

I don't bother putting _'s in the exponent because we can't have exponents 1000 and up. I have to do the [sreverse] bit because while we may have look-ahead regular expressions, we do not have look-behind.

AMG 2006-12-15: There is now a [string reverse] command.

RS proposes this simpler version of sreverse:
```proc sreverse str {
set res ""
set i [string length \$str]
while {\$i} {append res [string index \$str [incr i -1]]}
set res
}
% sreverse hello
olleh```

AMG: I saw that on the Additional string functions page, but I chose not to use it because even though it may be more efficient there's a few things I don't like about its style. (This doesn't reflect on your code, merely my preferences.)

• I feel that it's an abuse to consider 0 to be false and nonzero to be true. I always explicitly make the comparison with zero. Java requires this, by the way. I find this especially important when using [string compare], where a naive reader would assume that ![string compare] tests for string inequality.
• In many cases I dislike simultaneously using a command's side effect and its return value. Does [incr i -1] return the original value of \$i or the changed value? I know the answer, but I would like it to be evident from the code structure.
• [set res] bothers me because I'm accustomed to seeing [return]. I like being explicit about the fact that a proc returns a value, rather than relying on the (standard, documented) fall-off-the-bottom behavior.
• I always brace the second argument to [proc] because that reduces the chance of typo if I add arguments or defaults later on.

But I also see that my code's use of [expr] makes it hard to read. [for] is always funny, too. If not for the high price, I might consider using the [unknown] I mention at the bottom of the page of the same name, and write:
```proc sreverse {str} {
set result ""
foreach i [[expr {[string length \$str] - 1}]-0] {
append result [string index \$str \$i]
}
return \$result
}```

Hmm, that's pretty weird-lookin' too. Now you've got me wishing for \$(...) syntax for [expr], but we can never have that because it's already used for arrays named "". \$[...] maybe? Ah, I know how to do it without (explicit) [expr]. This is quite nice, I think:
```proc sreverse {str} {
set result ""
for {set i 0} {\$i < [string length \$str]} {incr i} {
append result [string index \$str end-\$i]
}
return \$result
}```

Oh, look what we've done. We hijacked SYStems's page and turned it into a style discussion! - RS keeps on the hijacking with a collecting wrapper for simple loops:
```proc loop {_var from to body} {
upvar 1 \$_var var
set res {}
for {set var \$from} {\$var < \$to} {incr var} {lappend res [uplevel 1 \$body]}
set res
}
% loop i 0 10 {set i}
0 1 2 3 4 5 6 7 8 9```

Then we can write:
```proc sreverse {str} {
join [loop i 0 [string length \$str] {string index \$str end-\$i}] ""
}

% sreverse hello
olleh```

Tcl 8.6 Wish List

Tcl/Tk Wish List

[Quoting]

[Quoting Styles]