## Converting numbers from arbitrary bases

Michael A. Cleverly - The other day someone on OpenACS.org asked [L1 ] for a Tcl proc that would convert a base-62 number into a base-10 integer. I replied with a version I'd written. Here is a slightly expanded one. convert_number employs some Salt and Sugar which I quite like.

(One caveat is that base_n_to_decimal will either return an incorrect answer or generate an error for really large numbers that are > than 2147483647.)

``` proc base_characters {base_n} {
set base [list 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M \
N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p \
q r s t u v w x y z]
if {\$base_n < 2 || \$base_n > 62} {
error "Invalid base \"\$base_n\" (should be an integer between 2 and 62)"
}
return [lrange \$base 0 [expr \$base_n - 1]]
}

proc base_n_to_decimal {number base_n} {
set base   [base_characters \$base_n]
# trim white space in case [format] is used
set number [string trim \$number]
# bases 11 through 36 can be treated in a case-insensitive fashion
if {\$base_n <= 36} {
set number [string toupper \$number]
}
set decimal 0
set power [string length \$number]

foreach char [split \$number ""] {
incr power -1
set dec_val [lsearch \$base \$char]
if {\$dec_val == -1} {
error "\$number is not a valid base \$base_n number"
}
set decimal [expr \$decimal + \$dec_val * int(pow(\$base_n,\$power))]
}

return \$decimal
}

proc decimal_to_base_n {number base_n} {
set base [base_characters \$base_n]
# trim white space in case [format] is used
set number [string trim \$number]

if {![string is integer \$number] || \$number < 0} {
error "\$number is not a base-10 integer between 0 and 2147483647"
}

while 1 {
set quotient  [expr \$number / \$base_n]
set remainder [expr \$number % \$base_n]
lappend remainders \$remainder
set number \$quotient
if {\$quotient == 0} {
break
}
}

set base_n [list]

for {set i [expr [llength \$remainders] - 1]} {\$i >= 0} {incr i -1} {
lappend base_n [lindex \$base [lindex \$remainders \$i]]
}

return [join \$base_n ""]

}

proc convert_number {number "from" "base" base_from "to" "base" base_to} {
return [decimal_to_base_n [base_n_to_decimal \$number \$base_from] \$base_to]
}```

Bryan Steimel - same thing as above for the most part, just what I managed to put together .. hopefully its helpful to someone. usage is hopefully self explanatory .. [to_base <num> <base>] and vice versa

```        variable base_chars "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
proc to_base {number base} {
variable base_chars
if {\$number==0} {
return 0
} elseif {((\$base>62) || (\$base<2))} {
return -code error "base: expected integer between 2 and 62, got '\$base'"
}
set nums [string range \$base_chars 0 [expr \$base - 1]]
set result ""
while {\$number > 0} {
set result "[string index \$nums [expr \$number % \$base]]\${result}"
set number [expr int(\$number / \$base)]
}
set result
}

proc from_base {number base} {
variable base_chars
if {((\$base>62) || (\$base<2))} {
return -code error "base: expected integer between 2 and 62, got '\$base'"
}
set nums [string range \$base_chars 0 [expr \$base - 1]]
for {
set result 0
set i 0
set len [string length \$number]
} {\$i<\$len} {
incr i
} {     incr i
set result [expr \$result * \$base]
set result [expr \$result + [string first [string index \$number \$i] \$nums]]
}
set result
} ```

LV I'm searching for a technique of transforming strings. The transformation is to take a string like "Abc" and transforming it into an ASCII string of base 2, and then code to do the reverse - to transform "0110000101101001" and so forth into a string of alphabetic (or whatever) characters. However, I don't know how clear that description is... Anyways, I'm trying to figure out exactly how to do this - do I need to use the above code along with binary, format and scan to accomplish what I'm aiming for?

FrankBannon - 2011-11-09 22:29:51

LV: you have helped me so many times I feel compelled to return the favor. One quick method to convert text to binary and back might be:

```# text to binary
proc text_to_bin str {
foreach s [split \$str ""] {
set dec [scan \$s %c]
set bin [decimal_to_base_n \$dec 2]
append output [format "%08s " \$bin]        ;# pad to 8 bits
}
return \$output
}

# binary to text
proc bin_to_text str {
foreach s \$str {
append output [format "%c" [scan \$s %b]]
}
return \$output
}

set binary [text_to_bin Tickle]
01010100 01101001 01100011 01101011 01101100 01100101
bin_to_text \$binary
Tickle```

 Category Mathematics Based numbers