Voting

Category

real language

Bookmarking

Del.icio.us Digg Diigo DZone Earthlink Google Kick.ie
Windows Live LookLater Ma.gnolia Reddit Rojo StumbleUpon Technorati

Support Us

Language bash

(Arithmetic on English words for numbers)

Date:07/31/08
Author:Bill Brown
URL:n/a
Comments:0
Info:n/a
Score: (3.00 in 2 votes)
#!/bin/bash
#A way-overcomplicated implementation of the bottles
# of beer song in bash.
#Optional argument: --careless   Generate the "happen to fall" version

standardBreakLine="Take one down and pass it around"
wastefulBreakLine="If one of those bottles should happen to fall"
breakLine=$([ "$1" = --careless ] && echo $wastefulBreakLine ||
                                     echo $standardBreakLine)

function pred() {  #get predecessor to a number
  case $1 in
    *nine)  echo ${1%nine}eight;;
    *eight) echo ${1%eight}seven;;
    *seven) echo ${1%seven}six;;
    *six)   echo ${1%six}five;;
    *five)  echo ${1%five}four;;
    *four)  echo ${1%four}three;;
    *three) echo ${1%three}two;;
    *two)   echo ${1%two}one;;
    one)    echo zero;;
    *-one)  echo ${1%-one};;
    *one)   echo ${1%one};;
    ten)    echo nine;;
    eleven) echo ten;;
    twelve) echo eleven;;
    *teen)  teenpred $1;;
    *ty)    tenspred $1;;
    zero)   echo "";  #to terminate
  esac
  }
  
function teenpred() { #predecessor of a teen
  case $1 in
     thirteen)   echo twelve;;
     *)     echo $(crunchprefix $(pred $(uncrunchprefix ${1%teen})))teen;;
     esac  
  }
  
function tenspred() { #predecessor of a multiple of ten
  case $1 in
     twenty)     echo nineteen;;
     *) echo $(crunchprefix --tens $(pred $(uncrunchprefix ${1%ty})))ty-nine;;
     esac  
  }
  
function crunchprefix() {
  #crunch number prefix to its conventional form
  # such as three --> thir
  # option --tens     multiples of ten are a bit different
  [ $1 = --tens ] && { tensop=true; shift; }
  case $1 in 
    two)   [ -n "$tensop" ] && echo twen || echo $1;;
    three) echo thir;;
    four)  [ -n "$tensop" ] && echo 'for' || echo $1;;
    five)  echo fif;;
    eight) [ -n "$tensop" ] && echo eigh || echo $1;;
    *)     echo $1;;
  esac
  }

function uncrunchprefix() { #reverse crunchprefix
  case $1 in
    twen)  echo two;;
    thir)  echo three;;
    'for') echo four;;
    fif)   echo five;;
    eigh)  echo eight;;
    *)     echo $1;;
  esac
  }
    
function grammar() { #peculiarities of English grammar
  local oneBottle=false  #can effect the following line
  while read line; do
    line="${line/one more bottles/one more bottle}"
    case "$line" in
       *"one of those bottles"*) line="$([ $oneBottle = true ] && 
                         echo ${line/one of those bottles/that lone bottle} ||
                         echo $line )"
                         ;;
       *"one down"*) line="$([ $oneBottle = true ] && 
                         echo ${line/one down/it down} ||
                         echo $line )"
                         ;;
       *bottles*)   oneBottle=false;;
       *bottle*)    oneBottle=true;;
       esac
      #Some say the twenties should have no hyphen
    line="${line/twenty-/twenty }"
    echo $line
    done
  }
  
function capitalize() {  #fix beginning of each line
  while read line; do
    echo -n ${line:0:1} | tr '[:lower:]' '[:upper:]'
    echo ${line#?}
    done
  }
function punctuate() {  #add punct to each line
  while read line; do 
    case "${line}" in
      [Ii]f*)   echo ${line},;;
      '')       echo;;
      *)        echo ${line}.;;
      esac
    done
  }

function verse () { #write one verse
  local nb=$1
  echo $nb bottles of beer on the wall
  echo $nb bottles of beer
  if [ $nb = zero ]; then
    echo Go to the store and buy some more
    nb=ninety-nine
  else
    echo $breakLine
    nb=$(pred $nb)
  fi
  echo $nb bottles of beer on the wall
  }
  
function poeticize() { #make it nice
  while read first rest; do
    case "$rest" in
      *beer*)
        first=${first/zero/no}
        local syl=$(syllables ${first% *})
        case $syl in  #improve meter
          1|2)   echo $first 'more' $rest;;
          *)     echo $first $rest;;
          esac;;
      *)         echo $first $rest
      esac
    done
  }
  
function syllables { #estimate number of syls in word
  local n=1
  case $1 in
    eleven)       n=2;; #sounds better if not considered 3
    *teen)        n=2;;
    *ty)          n=2;;
    *-*)          n=3;; #don't care about more than 3
    esac
  case $1 in
    *seven*)      let $((n = n+1));;
    esac
  echo $n
  }
    

nb=ninety-nine

while [ -n "$nb" ]; do
  verse $nb
  echo
  nb=$(pred $nb)
  done | poeticize | grammar | punctuate | capitalize

Download Source | Write Comment

Alternative Versions

VersionAuthorDateCommentsRate
No loop, no recursionFrédéric Lang07/08/083
Bourne Again ShellDave Plonka04/20/055
portable, rich of features, readableBastian Bittorf08/20/070
with arrays and functionsVittorio Cagnetta06/30/060
recursive functionKoen Noens12/30/070

Comments

Download Source | Write Comment

Add Comment

Please provide a value for the fields Name, Comment and Security Code.
This is a gravatar-friendly website.
E-mail addresses will never be shown.
Enter your e-mail address to use your gravatar.

Please don't post large portions of code here! Use the form to submit new examples or updates instead!

Name:

eMail:

URL:

Security Code:
  
Comment: