Monday, January 4, 2016

Numbers to Words! In Bash

#!/usr/bin/env bash

###     Copyrighted +A.M.Danischewski (c)2016+  
### You may reuse this software without limit provided 
###         this notice remain in tact. 
### Version: 1.03
### File: num2str.bsh   
###  Description: This script turns numbers into words! 
###     $> num2str.bsh 112975
###        One Hundred Twelve Thousand Nine Hundred Seventy Five
###     $> num2str.bsh 112975 anyflag ## More verbose! 
###        One Hundred Twelve Thousand Nine Hundred Seventy Fifth
###     $> num2str.bsh 1
###        One 
###     $> num2str.bsh 
###        First
###  _-=  Enjoy!  _-=  

declare -a units=("" "one" "two" "three" "four" "five" "six" "seven" \
                  "eight" "nine" "ten" "eleven" "twelve" "thirteen" "fourteen" \
                  "fifteen" "sixteen" "seventeen" "eighteen" "nineteen")            
declare -a tens=("" "" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety")
declare -a unitsverbose=("" "first" "second" "third" "fourth" "fifth" "sixth" \
                         "seventh" "eighth" "ninth" "tenth" "eleventh" "twelfth" "thirteenth" \
                         "fourteenth" "fifteenth" "sixteenth" "seventeenth" "eigteenth" \
                         "nineteenth")
declare numstr="${1}" 
declare rdlnk=$(readlink /proc/$$/fd/0)

if grep -Eq "^pipe:|deleted" <<< "${rdlnk}"; then 
 [[ ! -z "${numstr}" ]] && numstr="" && set -- ourdearflag again
 while IFS= read -r piped_input || break; do numstr="${numstr}${piped_input}"; done  
elif [[ -f "${rdlnk}" ]]; then 
 [[ ! -z "${numstr}" ]] && numstr="" && set -- ourdearflag again
 numstr=$(head -1 "${rdlnk}") ## Only line 14u, you want more than h4ck.
elif [[ -e "${numstr}" ]]; then 
 numstr=$(head -1 "${numstr}") ## File name proper no redirect.
fi 

function main() { 
 local tmpnum=""
 local tmpnumv="" 
 if (($# > 1)); then 
   ## If more than 2 digits, convert only the ((last digit) (if > 0)) or last 2 digits.
  if ((${#numstr} > 2)); then 
   tmpnumv=$(sed 's/^\(.*\)\(..$\)/\2/' <<< "$numstr")
   tmpnum="$(sed 's/..$//' <<< "$numstr")00"
   tmpnum=$(convert ${tmpnum})
   numstr=$((10#${tmpnumv}))
   tmpnumv=$(convert ${tmpnumv} "unitsverbose")
   ((${#numstr} == 2)) && ((${numstr}>19)) && ((${numstr:1:1}==0)) && tmpnumv="$(sed 's/y$//' <<< "${tmpnumv}")ieth"
   numstr="${tmpnum} ${tmpnumv}"
  elif ((${#numstr} == 2)) && ((${numstr}>19)); then 
    numstr="$(sed 's/y$//' <<< $(convert "${numstr}" "unitsverbose"))ieth"
  else ## Convert the whole number to verbose
   numstr=$(convert "$numstr" "unitsverbose")
  fi 
   grep -qEi 'hundred$|thousand$|million$|billion$' <<< "${numstr}" && numstr="${numstr}th"
 else ## Normal conversion 
   numstr=$(convert "$numstr") 
 fi 
  ## Temp, fix for 329478932 and other large numbers that may cause a double space. 
 sed 's/[ ]*$//;s/  / /g' <<< "${numstr}"
} 
   
function convert() {
local -i INTEGER=$((10#${1}))
local unitstype=${2:-"units"} ## units or unitsverbose
 if (($INTEGER < 0)); then 
   echo -en "minus "
   convert $(($INTEGER*-1)) 
elif (($INTEGER < 20)); then 
   eval echo -en \${${unitstype}[$INTEGER]}
elif (($INTEGER < 100)); then 
   echo -en ${tens[$(($INTEGER/10))]}  
   (($INTEGER%10)) && echo -en " "
   eval echo -en \${${unitstype}[$(($INTEGER%10))]}
elif (($INTEGER < 1000)); then 
   eval echo -en "\${${unitstype}[$(($INTEGER/100))]} hundred" 
   (($INTEGER%100)) && echo -en " "
   convert $(($INTEGER%100)) 
elif (($INTEGER < 1000000)); then 
   convert $(($INTEGER/1000))
   echo -en " thousand" 
   (($INTEGER%1000)) && echo -en " "
   convert $(($INTEGER%1000)) 
elif (($INTEGER < 1000000000)); then 
   convert $(($INTEGER/1000000))
   echo -en " million " 
   (($INTEGER%1000)) && echo -en " "
   convert $(($INTEGER%1000000)) 
else 
   convert $(($INTEGER/1000000000))
   echo -en " billion" 
   (($INTEGER%1000000000)) && echo -en " "
   convert $(($INTEGER%1000000000)) 
fi 
} 

main $@ | sed 's/^./\U&/;s/ [^ ]/\U&/g'
exit 0

No comments:

Post a Comment