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 gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Number formatting 2

Status
Not open for further replies.

ddrillich

Technical User
Jun 11, 2003
546
US
Good Day,

How can I format 1703 to 1,703?

Thank You,
Dan
 
The only way I could think of to do it when I wanted a similar function was to build a proc:
Code:
proc commaPrs {instrng} {
#strip off the decimal characters
  regexp {([0-9]*)(.[0-9]*)} $instrng match bodstr stend
  set lbod [string length $bodstr]
 #number of commas
  set A [expr int($lbod/3)]
  set R [expr int(fmod($lbod,3))]
  if {$R != 0} then {append ostrng [string range $instrng 0 [expr {$R-1}]]}
  if {$A == 0} then {
    append ostrng $stend
    return $ostrng
 }
  for {set i 1} {$i<=$A} {incr i} {
    set inx0 [expr ($i-1)*3 + $R ]
    set inx1 [expr $inx0 +2]
    if {($i==1) && ($R==0)} then {
      append ostrng [string range $instrng $inx0 $inx1]
    } else {
      append ostrng ,[string range $instrng $inx0 $inx1]
    }
  }
  append ostrng $stend
  return $ostrng
}

_________________
Bob Rashkin
rrashkin@csc.com
 
Good Day,

I just tried it and here are the results -

17030000 -> 1,703,0000

1703000 -> 170,3000

1703 -> 1703

I guess it needs a touch here and there :)

-- Dan
 
OOPS!
It didn't like that there was no fractional part. Try this:
Code:
proc commaPrs {instrng} {
#strip off the decimal characters
 regexp {([0-9]*)([red]\.[/red][0-9]*)} $instrng match bodstr stend
 [red]if [catch {set match}] {set bodstr $instrng; set stend ""}[/red]
 set lbod [string length $bodstr]
 #number of commas
 set A [expr int($lbod/3)]
 set R [expr int(fmod($lbod,3))]
 if {$R != 0} then {append ostrng [string range $instrng 0 [expr {$R-1}]]}
 if {$A == 0} then {
  append ostrng $stend
  return $ostrng
 }
 for {set i 1} {$i<=$A} {incr i} {
  set inx0 [expr ($i-1)*3 + $R ]
  set inx1 [expr $inx0 +2]
  if {($i==1) && ($R==0)} then {
    append ostrng [string range $instrng $inx0 $inx1]
  } else {
    append ostrng ,[string range $instrng $inx0 $inx1]
  }
 }
append ostrng $stend
 return $ostrng
}

_________________
Bob Rashkin
rrashkin@csc.com
 
What do you mean? It seems to be working with integers now when I try it.

_________________
Bob Rashkin
rrashkin@csc.com
 
Hi Bob,

[
proc commaPrs {instrng} {
#strip off the decimal characters
regexp {([0-9]*)(\.[0-9]*)} $instrng match bodstr stend
if [catch {set match}] {set bodstr $instrng; set stend ""}
set lbod [string length $bodstr]
#number of commas
set A [expr int($lbod/3)]
set R [expr int(fmod($lbod,3))]
if {$R != 0} then {append ostrng [string range $instrng 0 [expr {$R-1}]]}
if {$A == 0} then {
append ostrng $stend
return $ostrng
}
for {set i 1} {$i<=$A} {incr i} {
set inx0 [expr ($i-1)*3 + $R ]
set inx1 [expr $inx0 +2]
if {($i==1) && ($R==0)} then {
append ostrng [string range $instrng $inx0 $inx1]
} else {
append ostrng ,[string range $instrng $inx0 $inx1]
}
}
append ostrng $stend
return $ostrng
}

set x 1703
set y [commaPrs $x]

set y
]

returns 1703.

-- Dan
 
Not when I do it. I just copied from between the brackets ([]) in your post into a tclsh console. I got 1,703:
% set y [commaPrs $x]
1,703
%
% set y
1,703

_________________
Bob Rashkin
rrashkin@csc.com
 
It was a Vignette escape issue. I made this change, adding the extra escape -
regexp {([0-9]*)(\\.[0-9]*)} $instrng match bodstr stend

Thank You Bob!!

-- Dan
 
While I always think regexp is elegant and cool, it turns out when there's a way to do the same thing with string or list operations, it looks better that way. Therefore, after reconsidering, I think this is better:
Code:
proc commaPrs {instrng} {
#strip off the decimal characters
     set dl [split $instrng .]
     foreach {bodstr stend} $dl {}
     set lbod [string length $bodstr]
 #number of commas
     set A [expr int($lbod/3)]
     set R [expr int(fmod($lbod,3))]
     if {$R != 0} then {append ostrng [string range $instrng 0 [expr {$R-1}]]}
     if {$A == 0} then {
          return [join "$bodstr $stend" .]
     }
     for {set i 1} {$i<=$A} {incr i} {
          set inx0 [expr ($i-1)*3 + $R ]
          set inx1 [expr $inx0 +2]
          if {($i==1) && ($R==0)} then {
            append ostrng [string range $instrng $inx0 $inx1]
          } else {
            append ostrng ,[string range $instrng $inx0 $inx1]
          }
     }
     return [join "$ostrng $stend" .]
}

_________________
Bob Rashkin
rrashkin@csc.com
 
I couldn't resist. This is as tight as I can get it. No more math. No more conditionals. Anyone else?
Code:
proc commaPrs {instrng} {
#strip off the decimal characters
    set dl [split $instrng .]
    foreach {bodstr stend} $dl {}
#break body into "threes"
    while {[string length $bodstr]>0} {
        lappend l [string range $bodstr end-2 end]
        set bodstr [string range $bodstr 0 end-3]
    }
#reverse the list
    set i [llength $l]
    incr i -1
    while {$i>=0} {lappend l2 [lindex $l $i];incr i -1}
#regroup
    set ostrng [join $l2 ,]
    return [join "$ostrng $stend" .]
}

_________________
Bob Rashkin
rrashkin@csc.com
 
Beautiful thing Bob!

I fully agree with you about regexp.

-- Dan
 
whoa guys, waaaay too involved ...

try sending your value thru this function ...

proc Fmt_w_commas {x} {
set cs ","
while {[regsub {^([-+]?\d+)(\d\d\d)} $x "\\1$cs\\2" x]} {}
return $x
}

 
Excellent!
Now, for the regexp-challenged, could you explain the syntax?

_________________
Bob Rashkin
rrashkin@csc.com
 
Ok ...

The regexp has two separate parenthesized sub-expressions, each of which needs to be successfully matched for the while loop to continue.

The 1st parenthesized sub-expression, ^([-+]?\d+) is broken down like this:

^ --> at start of line
[-+] --> look for either a "-" or "+" sign
? --> find either 1 or zero occurances of the preceeding exp. (i.e. "[-+]")
\d --> look for digit(s)
+ --> find 1 or more of preceeding exp. (i.e. "\d")

The 2nd parenthesized sub-expression, (\d\d\d) is broken down like this:
\d\d\d --> simply says find 3 consectitive digits

The "\\1$cs\\2" section of the regsub cmd is the substitution specification value which simple reformats the matching value of the string prior to copying the entire string to the variable named "x". "\1" equates to the 1st parenthesized sub-expression, $cs is the separator value, and "\2" equates to the 2nd parenthesized sub-expression.

The key thing here is that only the matching portion of the string is reformated via the substitution specification value. The new string value (which includes the "matched" reformatted portion plus the "non-matched" portion), is then copied to the variable "x".

The loop continues until either of the parenthesized sub-expressions can't be matched.

example:
x= +8123567

Loop cycle #1:
1st parenthesized sub-expression = +8123
2nd parenthesized sub-expression = 567
x= +8123,567

Loop cycle #2:
1st parenthesized sub-expression = +8
2nd parenthesized sub-expression = 123
x= +8,123,567
 
very clever

_________________
Bob Rashkin
rrashkin@csc.com
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top