开发者

Handling numbers with leading zeros in Tcl

I am having trouble in Tcl using numbers with leading zeros. I am parsing some numbers that can have leading ze开发者_StackOverflow社区ros, such as "0012", which should be interpreted as the integer "twelve".

$ tclsh
% set a 8 
8
% set b 08
08
% expr $a - 1
7
% expr $b - 1
expected integer but got "08" (looks like invalid octal number)

What is the best way to handle numbers that might have a leading zeros in Tcl?

On a side note, what would constitute a valid octal number in Tcl, if "08" is an invalid one?


You'll want to read Tcl and Octal Numbers at the Tcl wiki. The canonical way is to treat your input as a string and use the scan command to extract the numbers. That leads to this, yes multiline, proc:

proc forceInteger { x } {
    set count [scan $x %d%s n rest]
    if { $count <= 0 || ( $count == 2 && ![string is space $rest] ) } {
        return -code error "not an integer: \"$x\""
    }
    return $n
}


This is the cleanest solution:

% expr [ scan "08" %d ] - 1
7

Furthermore:

% expr [ scan "09" %d ]
9
% expr [ scan 09 %d ]
9
% set nine 09
09
% expr [ scan $nine %d ]
9
% set success [ scan $nine %d number ]
1
% puts $number
9

scan : This is probably what you care about. Converts the "09" (even as a string) into a decimal number 9.

Note:
1. If this value cannot be converted into a decimal value, then scan will return an empty string ({}).
2. If a variable name is provided to the scan command (like the number variable in the example above), then the return value indicates status, 0: failed to parse decimal, and 1: success.

expr : Used here to demonstrate that expr interprets the value as a number, and addresses the original question. It evaluates an expression (e.g. expr {2*3} returns 6).


I have all these Tcl/Tk version 8.1 programs that have become broken because Tcl/Tk 8.5.10 is not handling string/numeric conversions correctly.

Here, shell into Tcl, and type:

 %  expr {01}
 1

(and so on..)

 %  expr {06}
 6

 %  expr {07}    
 7

and then we get to 8...

 %  expr {08}
 missing operator at "_@_"

looks like invalid octal number

But it gets worse. Still in Tcl shell, try this:

In my Tcl8.1 shell:

 % format "%.0f" {08}
 8

But in my new and improved Tcl8.5 shell, I get an error:

 % format "%.0f" {08}
 expected floating-point number but got "08" (looks like invalid octal number)

This is just goofy! I have all this code that works ok in Tcl7.6 and Tcl8.1, but which started giving weird, random results in Tcl8.5. Only when the number 08 happened to get generated or be used! I have spent hours trying to figure out the problem. But it turns out it is just a nasty sack of code that I am using!

So, I am posting this rant as a warning.
Tcl/Tk Version 8.5.10 handles the number eight incorrectly. If you are expecting sane behavior from your format statements, this will not happen. Your code will fly along, until it encounters a string valued at {08}, and the Tcl 8.5.10 interpreter will generate an error, because it will assume that {08} is a special-case octal number, regardless of the fact that all the other little numbers you have used will have worked just fine!

One possible solution to the problem mentioned above is to downgrade back to a Tcl 8.1 shell. I have confirmed that that version does at least handle format statements for the number 08 correctly. Tcl 8.5.10 shell simply does not.


set $clean_number [regsub {^0*(.+)} $troublesome_number {\1}] this doesnt work 
set clean_number "" 
set $troublesome_number 08
% set $clean_number [regsub {^0*(.+)} $troublesome_number {\1}]
wrong # args: should be "regsub ?switches? exp string subSpec varName"

an easier solution is:

set x 08
regsub {^[0]} $x {\1} x
puts $x
=>8


This link should help you

Valid octal numbers can only contain the digits 0-7 and must start with 0


Personally I've always used:

set $clean_number [regsub {^0*(.+)} $troublesome_number {\1}]

to sanitize $troublesome_numbers.


#!/bin/tclsh

#Regsub TCL script to remove the leading zeros from number. 
#Author : Shoeb Masood , Bagalore

puts "Enter the number"
set num [gets stdin]
regsub  {^0*} $num {\1} num
puts $num
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜